diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 50ce187..2f6eac5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -38,7 +38,7 @@
+
+
diff --git a/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt b/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt
index 9128989..aac0688 100644
--- a/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt
+++ b/app/src/main/java/com/sw/inbound/activity/FoodCollectionActivity.kt
@@ -10,7 +10,7 @@ import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
-import androidx.activity.ComponentActivity
+import com.sw.inbound.base.BaseActivity
import androidx.activity.viewModels
import androidx.camera.view.PreviewView
import androidx.core.view.updateLayoutParams
@@ -68,7 +68,7 @@ import java.io.File
*/
@SuppressLint("NotifyDataSetChanged")
@AndroidEntryPoint
-class FoodCollectionActivity : ComponentActivity() {
+class FoodCollectionActivity : BaseActivity() {
companion object {
const val TAG = "FoodCollectionActivity"
diff --git a/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt b/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt
index 4cb7c8e..e2bc48a 100644
--- a/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt
+++ b/app/src/main/java/com/sw/inbound/activity/GoodsListActivity.kt
@@ -9,7 +9,7 @@ import android.text.style.ForegroundColorSpan
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
-import androidx.activity.ComponentActivity
+import com.sw.inbound.base.BaseActivity
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.camera.view.PreviewView
@@ -70,7 +70,7 @@ import kotlin.math.min
typealias RecognizeCallback = (List) -> Unit
@AndroidEntryPoint
-abstract class GoodsListActivity : ComponentActivity() {
+abstract class GoodsListActivity : BaseActivity() {
companion object {
private const val TAG = "GoodsListActivity"
diff --git a/app/src/main/java/com/sw/inbound/activity/HomeActivity.kt b/app/src/main/java/com/sw/inbound/activity/HomeActivity.kt
new file mode 100644
index 0000000..0c685b6
--- /dev/null
+++ b/app/src/main/java/com/sw/inbound/activity/HomeActivity.kt
@@ -0,0 +1,131 @@
+package com.sw.inbound.activity
+
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import androidx.activity.viewModels
+import com.sw.inbound.base.BaseActivity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.sw.inbound.databinding.ActivityHomeBinding
+import com.sw.inbound.model.response.User
+import com.sw.inbound.objbox.FoodModule
+import com.sw.inbound.sdk.SensorScaleUtils
+import com.sw.inbound.utils.DateTimeUtils
+import com.sw.inbound.utils.ThreadUtils
+import com.sw.inbound.utils.ext.gone
+import com.sw.inbound.utils.ext.startActivity
+import com.sw.inbound.utils.ext.visible
+import com.sw.inbound.viewmodel.UserViewModel
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
+
+/**
+ * 首页 Activity(XML 版本)
+ * 对应原 HomeScreen.kt Compose 版本,原文件保留不动
+ * 功能:展示标题栏(含实时时间或用户信息)和两个功能入口(采购单入库、自采入库)
+ */
+@AndroidEntryPoint
+class HomeActivity : BaseActivity() {
+
+ private lateinit var binding: ActivityHomeBinding
+
+ /** 用于获取用户信息的 ViewModel */
+ private val viewModel: UserViewModel by viewModels()
+
+ /** 每秒刷新当前时间的 Handler */
+ private val handler = Handler(Looper.getMainLooper())
+
+ /** 时间刷新任务,每 1 秒更新一次标题栏右侧时间文字 */
+ private val timeRunnable = object : Runnable {
+ override fun run() {
+ binding.tvTime.text = DateTimeUtils.getChineseDateString()
+ handler.postDelayed(this, 1000)
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityHomeBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ initViews()
+ observeUser()
+ SensorScaleUtils.startScale(autoScale = true)
+ lifecycleScope.launch {
+ FoodModule.init(this@HomeActivity)
+ }
+ }
+
+ override fun onDestroy() {
+ SensorScaleUtils.closeScale()
+ ThreadUtils.release()
+ super.onDestroy()
+ }
+
+ /**
+ * 初始化各控件的点击事件
+ */
+ private fun initViews() {
+ // 标题点击:跳转菜品采集页面
+ binding.tvTitle.setOnClickListener {
+ startActivity()
+ }
+
+ // 采购单入库入口
+ binding.ivOrderPurchase.setOnClickListener {
+ startActivity()
+ }
+
+ // 自采入库入口,传入非采购单标志
+ binding.ivOrderSelfProcurement.setOnClickListener {
+ startActivity {
+ putExtra(GoodsListActivity.IS_RECEIPT_PAGE, false)
+ }
+ }
+ }
+
+ /**
+ * 观察用户登录状态,动态切换标题栏右侧显示内容:
+ * - 已登录:显示用户名 + 退出图标
+ * - 未登录:显示实时时间
+ */
+ private fun observeUser() {
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.user.collect { user ->
+ updateUserView(user)
+ }
+ }
+ }
+ }
+
+ /**
+ * 根据登录状态切换标题栏右侧 UI
+ * @param user 当前用户信息,为 null 表示未登录
+ */
+ private fun updateUserView(user: User?) {
+ if (user != null) {
+ // 已登录:显示用户名和退出图标,隐藏时间
+ binding.tvTime.gone()
+ binding.llUserInfo.visible()
+ binding.tvUserName.text = user.name ?: "用户"
+ } else {
+ // 未登录:显示实时时间,隐藏用户信息
+ binding.llUserInfo.gone()
+ binding.tvTime.visible()
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ // 页面可见时启动时间刷新
+ handler.post(timeRunnable)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ // 页面不可见时停止刷新,避免内存泄漏
+ handler.removeCallbacks(timeRunnable)
+ }
+}
diff --git a/app/src/main/java/com/sw/inbound/activity/LocalImagePreviewActivity.kt b/app/src/main/java/com/sw/inbound/activity/LocalImagePreviewActivity.kt
index e62d3e3..dd59d8a 100644
--- a/app/src/main/java/com/sw/inbound/activity/LocalImagePreviewActivity.kt
+++ b/app/src/main/java/com/sw/inbound/activity/LocalImagePreviewActivity.kt
@@ -4,7 +4,7 @@ import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
-import androidx.activity.ComponentActivity
+import com.sw.inbound.base.BaseActivity
import androidx.recyclerview.widget.GridLayoutManager
import coil.load
import com.chad.library.adapter4.BaseQuickAdapter
@@ -15,7 +15,7 @@ import com.sw.inbound.dialog.Loading
import com.sw.inbound.utils.ext.copyText
import java.io.File
-class LocalImagePreviewActivity : ComponentActivity() {
+class LocalImagePreviewActivity : BaseActivity() {
private lateinit var binding: ActivityLocalImagePreviewBinding
diff --git a/app/src/main/java/com/sw/inbound/activity/PurchaseOrderActivity.kt b/app/src/main/java/com/sw/inbound/activity/PurchaseOrderActivity.kt
index c13a034..20409dd 100644
--- a/app/src/main/java/com/sw/inbound/activity/PurchaseOrderActivity.kt
+++ b/app/src/main/java/com/sw/inbound/activity/PurchaseOrderActivity.kt
@@ -2,7 +2,7 @@ package com.sw.inbound.activity
import android.annotation.SuppressLint
import android.os.Bundle
-import androidx.activity.ComponentActivity
+import com.sw.inbound.base.BaseActivity
import androidx.activity.viewModels
import androidx.compose.runtime.collectAsState
import androidx.lifecycle.lifecycleScope
@@ -24,7 +24,7 @@ import kotlinx.coroutines.launch
* 采购单列表
*/
@AndroidEntryPoint
-class PurchaseOrderActivity : ComponentActivity() {
+class PurchaseOrderActivity : BaseActivity() {
private var list = mutableListOf()
private val adapter by lazy {
diff --git a/app/src/main/java/com/sw/inbound/base/BaseActivity.kt b/app/src/main/java/com/sw/inbound/base/BaseActivity.kt
new file mode 100644
index 0000000..c5e04e3
--- /dev/null
+++ b/app/src/main/java/com/sw/inbound/base/BaseActivity.kt
@@ -0,0 +1,51 @@
+package com.sw.inbound.base
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsControllerCompat
+
+/**
+ * 所有 Activity 的基类
+ * - 继承 ComponentActivity,保持与项目其他 Activity 一致
+ * - 自动隐藏状态栏和导航栏,实现全屏沉浸式体验
+ * - 在屏幕底部上滑时可临时唤出导航栏,松手后自动收回
+ */
+abstract class BaseActivity : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ hideSystemBars()
+ }
+
+ /**
+ * 窗口焦点变化时回调
+ * 场景:弹出 Dialog 后焦点丢失,Dialog 消失后焦点恢复,此时需重新隐藏系统栏,
+ * 避免系统栏在 Dialog 关闭后意外"复活"
+ */
+ override fun onWindowFocusChanged(hasFocus: Boolean) {
+ super.onWindowFocusChanged(hasFocus)
+ if (hasFocus) {
+ hideSystemBars()
+ }
+ }
+
+ /**
+ * 隐藏状态栏和导航栏
+ * 使用 WindowInsetsControllerCompat(Androidx 推荐方式,向下兼容性好)
+ * - 状态栏:完全隐藏
+ * - 导航栏:完全隐藏,底部上滑时临时出现,松手后自动收回(BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
+ */
+ private fun hideSystemBars() {
+ // 允许布局延伸到系统栏区域(edge-to-edge),避免内容被系统栏遮挡
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+ WindowInsetsControllerCompat(window, window.decorView).apply {
+ // 同时隐藏状态栏和导航栏
+ hide(WindowInsetsCompat.Type.systemBars())
+ // 底部上滑时临时显示导航栏,松手后自动隐藏(沉浸式 Sticky 模式)
+ systemBarsBehavior =
+ WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ }
+ }
+}
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
new file mode 100644
index 0000000..26dac8b
--- /dev/null
+++ b/app/src/main/res/layout/activity_home.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+