From e84d72dbf75e558b020d77dcab7199fd89fdb220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9C=E8=99=9E=E6=B8=A0=E6=88=90=E2=80=9D?= <“yuqucheng2006@qq.com”> Date: Tue, 1 Sep 2026 09:25:48 +0800 Subject: [PATCH] =?UTF-8?q?refactor(homepage):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=B8=BB=E9=A1=B5=E4=B8=8B=E6=8B=89=E5=88=B7=E6=96=B0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=86=E7=A0=81=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增HomePagePullRefreshTrigger组件实现全局下拉刷新 2. 调整Android最低SDK版本到31 3. 新增密码校验失败的多语言文案 4. 重构密码校验逻辑,添加异常捕获和统一的错误提示 5. 优化首页离线时的页面重置逻辑 --- Assets/Res/language/language.json | 5 ++ Assets/Res/ui/homepage/homePage.prefab | 32 ++++++++- .../Components/HomePagePullRefreshTrigger.cs | 31 +++++++++ .../HomePagePullRefreshTrigger.cs.meta | 11 +++ .../UI/Pages/HomePage/CheckPasswordPage.cs | 63 ++++++++++------- .../Scripts/UI/Pages/HomePage/HomePageCtrl.cs | 69 ++++++++++++++++++- ProjectSettings/ProjectSettings.asset | 2 +- 7 files changed, 183 insertions(+), 30 deletions(-) create mode 100644 Assets/Scripts/UI/Components/HomePagePullRefreshTrigger.cs create mode 100644 Assets/Scripts/UI/Components/HomePagePullRefreshTrigger.cs.meta diff --git a/Assets/Res/language/language.json b/Assets/Res/language/language.json index 180aa5d..b1539d0 100644 --- a/Assets/Res/language/language.json +++ b/Assets/Res/language/language.json @@ -199,6 +199,11 @@ "zh": "账号或密码错误,请重试", "en": "Incorrect account or password. Please try again." }, + { + "key": "home_password_check_failed", + "zh": "密码错误或校验失败,请重试", + "en": "Password incorrect or verification failed. Please try again." + }, { "key": "100041", "zh": "该邮箱已绑定至其他账号,请更换邮箱", diff --git a/Assets/Res/ui/homepage/homePage.prefab b/Assets/Res/ui/homepage/homePage.prefab index 89138e5..44fa832 100644 --- a/Assets/Res/ui/homepage/homePage.prefab +++ b/Assets/Res/ui/homepage/homePage.prefab @@ -7955,6 +7955,7 @@ GameObject: - component: {fileID: 6551506190466531803} - component: {fileID: 3881773501436982883} - component: {fileID: 6647875750186480783} + - component: {fileID: 2568189713370643574} m_Layer: 5 m_Name: "\u65E0\u8BBE\u5907" m_TagString: Untagged @@ -8004,7 +8005,7 @@ MonoBehaviour: m_EditorClassIdentifier: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 0 + m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: @@ -8020,6 +8021,18 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 +--- !u!114 &2568189713370643574 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3582556473535289502} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 432e8b6f5f7dd7a4f94d9c3b85c8b262, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &3686991546777705807 GameObject: m_ObjectHideFlags: 0 @@ -15843,7 +15856,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 0} - m_AnchoredPosition: {x: -9.000002, y: 10} + m_AnchoredPosition: {x: -9, y: 10} m_SizeDelta: {x: -57.999992, y: 55} m_Pivot: {x: 0.5, y: 0} --- !u!222 &3186938245855593830 @@ -16935,6 +16948,8 @@ MonoBehaviour: m_EditorClassIdentifier: noDevicePage: {fileID: 3582556473535289502} normalPage: {fileID: 8115864904787809625} + normalScrollRect: {fileID: 7398385099859628837} + pullTriggerDistance: 120 selectDeviceButton: {fileID: 1920078014523356616} selectDevicePage: {fileID: 2340476075600265632} selectCountryPage: {fileID: 1196293823344848224, guid: 90501a08c2cf82c4187b5f13c391291f, @@ -17117,6 +17132,7 @@ GameObject: - component: {fileID: 2697609740981075072} - component: {fileID: 928882153762487195} - component: {fileID: 7398385099859628837} + - component: {fileID: 5876146908749457361} m_Layer: 5 m_Name: "\u6B63\u5E38" m_TagString: Untagged @@ -17225,6 +17241,18 @@ MonoBehaviour: m_OnValueChanged: m_PersistentCalls: m_Calls: [] +--- !u!114 &5876146908749457361 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8115864904787809625} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 432e8b6f5f7dd7a4f94d9c3b85c8b262, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &8135258645254993493 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/UI/Components/HomePagePullRefreshTrigger.cs b/Assets/Scripts/UI/Components/HomePagePullRefreshTrigger.cs new file mode 100644 index 0000000..c597bf1 --- /dev/null +++ b/Assets/Scripts/UI/Components/HomePagePullRefreshTrigger.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using Kill.UI.Pages; + +namespace Kill.UI.Components +{ + /// + /// 下拉刷新触发器:挂到主页 ScrollRect(带 Image 的 Graphic)上,接收 EventSystem + /// 拖拽事件并转发给 HomePageCtrl。这样在滚动区域内任意位置都可触发下拉刷新。 + /// + public class HomePagePullRefreshTrigger : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler + { + public void OnBeginDrag(PointerEventData eventData) + { + var ctrl = HomePageCtrl.Instance; + if (ctrl != null) ctrl.OnPullRefreshBeginDrag(); + } + + public void OnDrag(PointerEventData eventData) + { + var ctrl = HomePageCtrl.Instance; + if (ctrl != null) ctrl.OnPullRefreshDrag(eventData.delta.y); + } + + public void OnEndDrag(PointerEventData eventData) + { + var ctrl = HomePageCtrl.Instance; + if (ctrl != null) ctrl.OnPullRefreshEndDrag(); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/UI/Components/HomePagePullRefreshTrigger.cs.meta b/Assets/Scripts/UI/Components/HomePagePullRefreshTrigger.cs.meta new file mode 100644 index 0000000..e820243 --- /dev/null +++ b/Assets/Scripts/UI/Components/HomePagePullRefreshTrigger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 432e8b6f5f7dd7a4f94d9c3b85c8b262 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/Pages/HomePage/CheckPasswordPage.cs b/Assets/Scripts/UI/Pages/HomePage/CheckPasswordPage.cs index e805d94..271e459 100644 --- a/Assets/Scripts/UI/Pages/HomePage/CheckPasswordPage.cs +++ b/Assets/Scripts/UI/Pages/HomePage/CheckPasswordPage.cs @@ -24,34 +24,45 @@ namespace Kill.UI.Pages { errorText.text=""; LoadingUI.Show(); - string password = passwordInput != null ? passwordInput.text : ""; - if (string.IsNullOrEmpty(password)) + try { - errorText.text = LanguageManager.Instance.GetLanguage("100040"); + string password = passwordInput != null ? passwordInput.text : ""; + if (string.IsNullOrEmpty(password)) + { + errorText.text = LanguageManager.Instance.GetLanguage("home_password_check_failed"); + return; + } + PasswordRequest requestData=new PasswordRequest + { + password=passwordInput.text + }; + + var response = await NetworkCtrl.Instance.Post("/api/v1/auth/password/verify", requestData); + + if (response != null && response.Data != null && response.Data.code == 200) + { + plane.SetActive(false); + gameObject.SetActive(false); + errorText.text=""; + passwordInput.text=""; + UIManager.Instance.isFirstTime=false; + } + else + { + errorText.text = LanguageManager.Instance.GetLanguage("home_password_check_failed"); + passwordInput.text=""; + } + } + catch (System.Exception ex) + { + Debug.LogError($"[CheckPasswordPage] 校验密码异常: {ex.Message}"); + errorText.text = LanguageManager.Instance.GetLanguage("home_password_check_failed"); + if (passwordInput != null) passwordInput.text = ""; + } + finally + { + // 无论成功/失败/异常都关闭 Loading,避免一直挂着 LoadingUI.Hide(); - return; - } - PasswordRequest requestData=new PasswordRequest - { - password=passwordInput.text - }; - - var response = await NetworkCtrl.Instance.Post("/api/v1/auth/password/verify", requestData); - - LoadingUI.Hide(); - - if (response.Data.code == 200) - { - plane.SetActive(false); - gameObject.SetActive(false); - errorText.text=""; - passwordInput.text=""; - UIManager.Instance.isFirstTime=false; - } - else - { - errorText.text = LanguageManager.Instance.GetLanguage("100040"); - passwordInput.text=""; } } diff --git a/Assets/Scripts/UI/Pages/HomePage/HomePageCtrl.cs b/Assets/Scripts/UI/Pages/HomePage/HomePageCtrl.cs index dc23d38..831efcb 100644 --- a/Assets/Scripts/UI/Pages/HomePage/HomePageCtrl.cs +++ b/Assets/Scripts/UI/Pages/HomePage/HomePageCtrl.cs @@ -21,6 +21,13 @@ namespace Kill.UI.Pages public GameObject noDevicePage; public GameObject normalPage; + // 下拉刷新:滚动区域 ScrollRect(用于判断内容是否在最顶部);无设备页可不填 + public ScrollRect normalScrollRect; + // 下拉刷新参数 + [SerializeField] private float pullTriggerDistance = 120f; // 触发刷新的拖动距离(像素) + private float pullDistance; // 当前累积下拉距离 + private bool isPullingAtTop; // 拖动开始时是否在内容顶部 + private bool isRefreshing; // 存储待执行的UI更新操作 private List pendingUIUpdates = new List(); public Button selectDeviceButton; @@ -477,6 +484,7 @@ namespace Kill.UI.Pages /// /// 网络断开:立刻把 WiFi 设备标离线并刷新 UI + /// 设备离线导致的 UI 重置由后台轮询触发,避免此处重复 Init /// private void OnNetworkDisconnectedHandler(object sender, EventArgs e) { @@ -1878,11 +1886,14 @@ namespace Kill.UI.Pages // WiFi和蓝牙都断开 if (wasOnline) { - Debug.Log("[HomePageCtrl] 设备WiFi离线"); + Debug.Log("[HomePageCtrl] 设备WiFi离线,重新加载首页"); pendingUIUpdates.Add(() => { deviceState?.UpdateDeviceState(hasBluetooth, hasWifi); }); + // 设备由在线变为离线且无蓝牙连接 → 直接重新加载首页 + UIManager.Instance.OpenMainPage(UIManager.PageName.homePage); + return; // 旧页面即将销毁,结束轮询 } else { @@ -1938,6 +1949,62 @@ namespace Kill.UI.Pages pendingUIUpdates.Add(action); } + #region 下拉刷新(由 HomePagePullRefreshTrigger 组件转发调用) + + public void OnPullRefreshBeginDrag() + { + if (isRefreshing) return; + isPullingAtTop = IsContentAtTop(); + pullDistance = 0f; + } + + public void OnPullRefreshDrag(float deltaY) + { + if (isRefreshing || !isPullingAtTop) return; + if (deltaY < 0) + { + pullDistance += -deltaY; + } + } + + public void OnPullRefreshEndDrag() + { + if (isRefreshing) return; + if (pullDistance >= pullTriggerDistance) + { + TriggerPullRefresh(); + } + else + { + ResetPullRefreshUI(); + } + isPullingAtTop = false; + } + + /// + /// 判断 ScrollRect 内容是否已在顶部(无 ScrollRect 时视为可下拉) + /// + private bool IsContentAtTop() + { + if (normalScrollRect == null) return true; + return normalScrollRect.verticalNormalizedPosition >= 0.999f; + } + + private void TriggerPullRefresh() + { + if (isRefreshing) return; + isRefreshing = true; + // 重新加载首页(销毁旧实例并实例化新实例,触发 Start/Init 重新跑) + UIManager.Instance.OpenMainPage(UIManager.PageName.homePage); + } + + private void ResetPullRefreshUI() + { + pullDistance = 0f; + } + + #endregion + /// /// 从WiFi刷新主页定时任务显示 /// diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 4cb3683..7fcc8c2 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -173,7 +173,7 @@ PlayerSettings: tvOS: 0 overrideDefaultApplicationIdentifier: 1 AndroidBundleVersionCode: 4 - AndroidMinSdkVersion: 33 + AndroidMinSdkVersion: 31 AndroidTargetSdkVersion: 36 AndroidPreferredInstallLocation: 0 aotOptions: