From 7047c51a0717e8b84c511ca374e055e08ccd816e Mon Sep 17 00:00:00 2001 From: tigerenwork Date: Sun, 5 Jul 2026 16:14:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B5=AE=E5=8A=A8=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E9=80=82=E5=BA=94=E5=B0=BA=E5=AF=B8?= =?UTF-8?q?=E5=B9=B6=E9=94=9A=E5=AE=9A=E5=8F=B3=E4=B8=8B=E8=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Bugger.xcodeproj/project.pbxproj | 237 +++++++++--------- .../FloatingWidget/FloatingWidgetWindow.swift | 66 ++++- 2 files changed, 184 insertions(+), 119 deletions(-) diff --git a/Bugger.xcodeproj/project.pbxproj b/Bugger.xcodeproj/project.pbxproj index 7ceb86b..0192e2d 100644 --- a/Bugger.xcodeproj/project.pbxproj +++ b/Bugger.xcodeproj/project.pbxproj @@ -7,68 +7,68 @@ objects = { /* Begin PBXBuildFile section */ - F6750BB1FBEE5BC90DD6BDBC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 207CA4381D0CFEC95263A2DE; }; - 15550246A9E8DAF25E690478 /* BuggerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB7AD270E93EA343975AC6; }; - 58F16D20CC26D8248055CC2C /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBEF4F77A6A2E2D041EF581; }; - 4EA9BDBA3F98AF4A41712A18 /* Bug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846CA001267896C54A78441A; }; - DDB9EB345FEBB95DD9976364 /* BugChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B24E1E1D32F7B774D12DD85; }; - A33561284CA44A0045902BCC /* BugPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5359156BD70B765D2BF4E718; }; - E4CBAE27491AF1C52944FA91 /* BugStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646C676356A4125B8E8D5FA5; }; - D2855F82E68FADA8BEA43086 /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1DD178095EFCE7BC121C1C4; }; - 4309E8C70AE99466545A3E37 /* FeishuAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A2C50E47966E8ADB0446A0C; }; - CB529549DB1DBB5F02884300 /* FeishuError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A83E76FBB83849E4B6704D3; }; - CAE624453A3F0375D872170A /* FeishuModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE9FBC39502FA635EF1A6A5C; }; - 29EE2FE56882F97E14AAF58F /* FeishuService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21AC33F380B7DC34C39B61A6; }; - 6148104B311B60C79B3B8572 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CC175DE8E9FE3250757D33; }; - 56D44DCBAF4FE0E1D9E620FA /* PollerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F4628E7B599B69B499E09E9; }; - B882D310EB2B5D032375CDDF /* TokenManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E3775F77DD36C27160A8C; }; - C5D9B1FACE813CD43236BB77 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F99094B0F609809EBDB5F4A; }; - 29AE37B117A1422EA21570CA /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C935E6B4D1813AB01186A0; }; - 64F1EE978536D1CB02B8F0D3 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF06E1030AA21DA8190169A8; }; - EEC5853D00ED565270DC867F /* LocalOAuthServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D11523ACB81DBB9D412995; }; - 47ED652FA0AC818086F85DF3 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED0A90DFCB8D4968E4E3CA1; }; - 1FB7E762C0B6568C47B48EF0 /* URL+Feishu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F888AA5F655343B19839B4C2; }; - AECED74595B57A400437B9FD /* BugStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344F52FB34B285D91A3E4670; }; - 485A69E15EF1D805F50DF364 /* FloatingWidgetWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E2FE32B404AB4388A066991; }; - 1E3C1F40E2FF64A041856909 /* BugListPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEABFC668F7B082847F65D38; }; - 3467A50268399ABE9804D4D4 /* BugRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1129D6F630904F03D06B5DC4; }; - B066D78DA6F57A882A61C0B2 /* OAuthSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0A744D4F5DB88B1496176B; }; - 7B0EAA6D83D40A593E36EE31 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3693AA93F823859D15256D; }; - C3F7FEB179B079BDDD2AA212 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 09B9A4D84F3F604C49171A89; }; + 15550246A9E8DAF25E690478 /* BuggerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB7AD270E93EA343975AC6 /* BuggerApp.swift */; }; + 1E3C1F40E2FF64A041856909 /* BugListPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEABFC668F7B082847F65D38 /* BugListPopover.swift */; }; + 1FB7E762C0B6568C47B48EF0 /* URL+Feishu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F888AA5F655343B19839B4C2 /* URL+Feishu.swift */; }; + 29AE37B117A1422EA21570CA /* DateFormatter+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C935E6B4D1813AB01186A0 /* DateFormatter+Extensions.swift */; }; + 29EE2FE56882F97E14AAF58F /* FeishuService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21AC33F380B7DC34C39B61A6 /* FeishuService.swift */; }; + 3467A50268399ABE9804D4D4 /* BugRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1129D6F630904F03D06B5DC4 /* BugRow.swift */; }; + 4309E8C70AE99466545A3E37 /* FeishuAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A2C50E47966E8ADB0446A0C /* FeishuAuthService.swift */; }; + 47ED652FA0AC818086F85DF3 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED0A90DFCB8D4968E4E3CA1 /* Logger.swift */; }; + 485A69E15EF1D805F50DF364 /* FloatingWidgetWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E2FE32B404AB4388A066991 /* FloatingWidgetWindow.swift */; }; + 4EA9BDBA3F98AF4A41712A18 /* Bug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846CA001267896C54A78441A /* Bug.swift */; }; + 56D44DCBAF4FE0E1D9E620FA /* PollerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F4628E7B599B69B499E09E9 /* PollerService.swift */; }; + 58F16D20CC26D8248055CC2C /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBEF4F77A6A2E2D041EF581 /* AppConfig.swift */; }; + 6148104B311B60C79B3B8572 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CC175DE8E9FE3250757D33 /* NotificationService.swift */; }; + 64F1EE978536D1CB02B8F0D3 /* KeychainHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF06E1030AA21DA8190169A8 /* KeychainHelper.swift */; }; + 7B0EAA6D83D40A593E36EE31 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3693AA93F823859D15256D /* SettingsView.swift */; }; + A33561284CA44A0045902BCC /* BugPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5359156BD70B765D2BF4E718 /* BugPriority.swift */; }; + AECED74595B57A400437B9FD /* BugStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344F52FB34B285D91A3E4670 /* BugStore.swift */; }; + B066D78DA6F57A882A61C0B2 /* OAuthSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */; }; + B882D310EB2B5D032375CDDF /* TokenManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E3775F77DD36C27160A8C /* TokenManager.swift */; }; + C3F7FEB179B079BDDD2AA212 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 09B9A4D84F3F604C49171A89 /* Assets.xcassets */; }; + C5D9B1FACE813CD43236BB77 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F99094B0F609809EBDB5F4A /* Color+Extensions.swift */; }; + CAE624453A3F0375D872170A /* FeishuModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE9FBC39502FA635EF1A6A5C /* FeishuModels.swift */; }; + CB529549DB1DBB5F02884300 /* FeishuError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A83E76FBB83849E4B6704D3 /* FeishuError.swift */; }; + D2855F82E68FADA8BEA43086 /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1DD178095EFCE7BC121C1C4 /* AppStateService.swift */; }; + DDB9EB345FEBB95DD9976364 /* BugChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B24E1E1D32F7B774D12DD85 /* BugChange.swift */; }; + E4CBAE27491AF1C52944FA91 /* BugStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646C676356A4125B8E8D5FA5 /* BugStatus.swift */; }; + EEC5853D00ED565270DC867F /* LocalOAuthServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D11523ACB81DBB9D412995 /* LocalOAuthServer.swift */; }; + F6750BB1FBEE5BC90DD6BDBC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 207CA4381D0CFEC95263A2DE /* AppDelegate.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - EF0182DF85A7CD0319333F24 /* Bugger.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bugger.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 207CA4381D0CFEC95263A2DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - DDDB7AD270E93EA343975AC6 /* BuggerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuggerApp.swift; sourceTree = ""; }; - 9FBEF4F77A6A2E2D041EF581 /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfig.swift; sourceTree = ""; }; - 846CA001267896C54A78441A /* Bug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bug.swift; sourceTree = ""; }; - 0B24E1E1D32F7B774D12DD85 /* BugChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugChange.swift; sourceTree = ""; }; - 5359156BD70B765D2BF4E718 /* BugPriority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugPriority.swift; sourceTree = ""; }; - 646C676356A4125B8E8D5FA5 /* BugStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugStatus.swift; sourceTree = ""; }; - F1DD178095EFCE7BC121C1C4 /* AppStateService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateService.swift; sourceTree = ""; }; - 6A2C50E47966E8ADB0446A0C /* FeishuAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuAuthService.swift; sourceTree = ""; }; - 2A83E76FBB83849E4B6704D3 /* FeishuError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuError.swift; sourceTree = ""; }; - FE9FBC39502FA635EF1A6A5C /* FeishuModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuModels.swift; sourceTree = ""; }; - 21AC33F380B7DC34C39B61A6 /* FeishuService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuService.swift; sourceTree = ""; }; - 59CC175DE8E9FE3250757D33 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; - 4F4628E7B599B69B499E09E9 /* PollerService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollerService.swift; sourceTree = ""; }; - 0E7E3775F77DD36C27160A8C /* TokenManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenManager.swift; sourceTree = ""; }; - 0F99094B0F609809EBDB5F4A /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = ""; }; - 87C935E6B4D1813AB01186A0 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; - EF06E1030AA21DA8190169A8 /* KeychainHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainHelper.swift; sourceTree = ""; }; - 34D11523ACB81DBB9D412995 /* LocalOAuthServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalOAuthServer.swift; sourceTree = ""; }; - 0ED0A90DFCB8D4968E4E3CA1 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; - F888AA5F655343B19839B4C2 /* URL+Feishu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Feishu.swift"; sourceTree = ""; }; - 344F52FB34B285D91A3E4670 /* BugStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugStore.swift; sourceTree = ""; }; - 6E2FE32B404AB4388A066991 /* FloatingWidgetWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingWidgetWindow.swift; sourceTree = ""; }; - CEABFC668F7B082847F65D38 /* BugListPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugListPopover.swift; sourceTree = ""; }; - 1129D6F630904F03D06B5DC4 /* BugRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugRow.swift; sourceTree = ""; }; - 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthSetupView.swift; sourceTree = ""; }; - 2D3693AA93F823859D15256D /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 09B9A4D84F3F604C49171A89 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 0B24E1E1D32F7B774D12DD85 /* BugChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugChange.swift; sourceTree = ""; }; + 0E7E3775F77DD36C27160A8C /* TokenManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenManager.swift; sourceTree = ""; }; + 0ED0A90DFCB8D4968E4E3CA1 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; + 0F99094B0F609809EBDB5F4A /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = ""; }; + 1129D6F630904F03D06B5DC4 /* BugRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugRow.swift; sourceTree = ""; }; + 207CA4381D0CFEC95263A2DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 21AC33F380B7DC34C39B61A6 /* FeishuService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuService.swift; sourceTree = ""; }; + 2A83E76FBB83849E4B6704D3 /* FeishuError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuError.swift; sourceTree = ""; }; + 2D3693AA93F823859D15256D /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 344F52FB34B285D91A3E4670 /* BugStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugStore.swift; sourceTree = ""; }; + 34D11523ACB81DBB9D412995 /* LocalOAuthServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalOAuthServer.swift; sourceTree = ""; }; + 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthSetupView.swift; sourceTree = ""; }; + 4F4628E7B599B69B499E09E9 /* PollerService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollerService.swift; sourceTree = ""; }; + 5359156BD70B765D2BF4E718 /* BugPriority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugPriority.swift; sourceTree = ""; }; + 59CC175DE8E9FE3250757D33 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; + 646C676356A4125B8E8D5FA5 /* BugStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugStatus.swift; sourceTree = ""; }; + 6A2C50E47966E8ADB0446A0C /* FeishuAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuAuthService.swift; sourceTree = ""; }; + 6E2FE32B404AB4388A066991 /* FloatingWidgetWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingWidgetWindow.swift; sourceTree = ""; }; 73AB234B54673C838E33AC7F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 846CA001267896C54A78441A /* Bug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bug.swift; sourceTree = ""; }; + 87C935E6B4D1813AB01186A0 /* DateFormatter+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extensions.swift"; sourceTree = ""; }; + 9FBEF4F77A6A2E2D041EF581 /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfig.swift; sourceTree = ""; }; + CEABFC668F7B082847F65D38 /* BugListPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugListPopover.swift; sourceTree = ""; }; + DDDB7AD270E93EA343975AC6 /* BuggerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuggerApp.swift; sourceTree = ""; }; E9B6FE6E06295095649B24A7 /* Bugger.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Bugger.entitlements; sourceTree = ""; }; + EF0182DF85A7CD0319333F24 /* Bugger.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bugger.app; sourceTree = BUILT_PRODUCTS_DIR; }; + EF06E1030AA21DA8190169A8 /* KeychainHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainHelper.swift; sourceTree = ""; }; + F1DD178095EFCE7BC121C1C4 /* AppStateService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateService.swift; sourceTree = ""; }; + F888AA5F655343B19839B4C2 /* URL+Feishu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Feishu.swift"; sourceTree = ""; }; + FE9FBC39502FA635EF1A6A5C /* FeishuModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeishuModels.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -82,7 +82,7 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 14ED1DECD6D906F498B9ECB5 /* Root */ = { + 14ED1DECD6D906F498B9ECB5 = { isa = PBXGroup; children = ( 287BE755981C092238309A9A /* Sources */, @@ -105,6 +105,17 @@ path = Sources; sourceTree = ""; }; + 31DF436612EC1C3CD1194AA1 /* Views */ = { + isa = PBXGroup; + children = ( + E7E4AD241EEE594C1EEB9724 /* FloatingWidget */, + EA9ED591BB8A18FEBD1B58A3 /* MenuBar */, + 74AD95EF49A7D01C83865FAC /* OAuth */, + B70D2E54AD6B19DD455A8F82 /* Settings */, + ); + path = Views; + sourceTree = ""; + }; 65997CD9BD6FFEF8851BF59E /* Models */ = { isa = PBXGroup; children = ( @@ -117,16 +128,30 @@ path = Models; sourceTree = ""; }; - A8C46168E4DFCE29B056A4E2 /* Services */ = { + 6AB9730AA11690EFC8F21473 /* ViewModels */ = { isa = PBXGroup; children = ( - F1DD178095EFCE7BC121C1C4 /* AppStateService.swift */, - 59CC175DE8E9FE3250757D33 /* NotificationService.swift */, - 4F4628E7B599B69B499E09E9 /* PollerService.swift */, - 0E7E3775F77DD36C27160A8C /* TokenManager.swift */, - E0E23D3899D89889546FB428 /* Feishu */, + 344F52FB34B285D91A3E4670 /* BugStore.swift */, ); - path = Services; + path = ViewModels; + sourceTree = ""; + }; + 74AD95EF49A7D01C83865FAC /* OAuth */ = { + isa = PBXGroup; + children = ( + 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */, + ); + path = OAuth; + sourceTree = ""; + }; + 8AD6A16612A2DB7B2F899787 /* Resources */ = { + isa = PBXGroup; + children = ( + 09B9A4D84F3F604C49171A89 /* Assets.xcassets */, + 73AB234B54673C838E33AC7F /* Info.plist */, + E9B6FE6E06295095649B24A7 /* Bugger.entitlements */, + ); + path = Resources; sourceTree = ""; }; A6646A2065F53ED50AD2CCA7 /* Utils */ = { @@ -142,23 +167,32 @@ path = Utils; sourceTree = ""; }; - 6AB9730AA11690EFC8F21473 /* ViewModels */ = { + A8C46168E4DFCE29B056A4E2 /* Services */ = { isa = PBXGroup; children = ( - 344F52FB34B285D91A3E4670 /* BugStore.swift */, + F1DD178095EFCE7BC121C1C4 /* AppStateService.swift */, + 59CC175DE8E9FE3250757D33 /* NotificationService.swift */, + 4F4628E7B599B69B499E09E9 /* PollerService.swift */, + 0E7E3775F77DD36C27160A8C /* TokenManager.swift */, + E0E23D3899D89889546FB428 /* Feishu */, ); - path = ViewModels; + path = Services; sourceTree = ""; }; - 31DF436612EC1C3CD1194AA1 /* Views */ = { + B23D89B2D2DF3745A003AEB1 /* Products */ = { isa = PBXGroup; children = ( - E7E4AD241EEE594C1EEB9724 /* FloatingWidget */, - EA9ED591BB8A18FEBD1B58A3 /* MenuBar */, - 74AD95EF49A7D01C83865FAC /* OAuth */, - B70D2E54AD6B19DD455A8F82 /* Settings */, + EF0182DF85A7CD0319333F24 /* Bugger.app */, ); - path = Views; + name = Products; + sourceTree = ""; + }; + B70D2E54AD6B19DD455A8F82 /* Settings */ = { + isa = PBXGroup; + children = ( + 2D3693AA93F823859D15256D /* SettingsView.swift */, + ); + path = Settings; sourceTree = ""; }; E0E23D3899D89889546FB428 /* Feishu */ = { @@ -189,40 +223,6 @@ path = MenuBar; sourceTree = ""; }; - 74AD95EF49A7D01C83865FAC /* OAuth */ = { - isa = PBXGroup; - children = ( - 3C0A744D4F5DB88B1496176B /* OAuthSetupView.swift */, - ); - path = OAuth; - sourceTree = ""; - }; - B70D2E54AD6B19DD455A8F82 /* Settings */ = { - isa = PBXGroup; - children = ( - 2D3693AA93F823859D15256D /* SettingsView.swift */, - ); - path = Settings; - sourceTree = ""; - }; - 8AD6A16612A2DB7B2F899787 /* Resources */ = { - isa = PBXGroup; - children = ( - 09B9A4D84F3F604C49171A89 /* Assets.xcassets */, - 73AB234B54673C838E33AC7F /* Info.plist */, - E9B6FE6E06295095649B24A7 /* Bugger.entitlements */, - ); - path = Resources; - sourceTree = ""; - }; - B23D89B2D2DF3745A003AEB1 /* Products */ = { - isa = PBXGroup; - children = ( - EF0182DF85A7CD0319333F24 /* Bugger.app */, - ); - name = Products; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -354,12 +354,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 2; - FEISHU_APP_ID = "$(FEISHU_APP_ID)"; - FEISHU_APP_SECRET = "$(FEISHU_APP_SECRET)"; - FEISHU_BASE_DOMAIN = "xorbitlab.feishu.cn"; + FEISHU_APP_ID = cli_aacb82a1c0b8dcc0; + FEISHU_APP_SECRET = jUkU9ygRuQ0KaZFV2BSPfe33iXCahzNM; + FEISHU_BASE_DOMAIN = xmi5p6bgsnf8.feishu.cn; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = Resources/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 1.1; PRODUCT_BUNDLE_IDENTIFIER = com.xorbitlab.bugger; @@ -375,12 +378,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 2; - FEISHU_APP_ID = "$(FEISHU_APP_ID)"; - FEISHU_APP_SECRET = "$(FEISHU_APP_SECRET)"; - FEISHU_BASE_DOMAIN = "xorbitlab.feishu.cn"; + FEISHU_APP_ID = cli_aacb82a1c0b8dcc0; + FEISHU_APP_SECRET = jUkU9ygRuQ0KaZFV2BSPfe33iXCahzNM; + FEISHU_BASE_DOMAIN = xmi5p6bgsnf8.feishu.cn; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = Resources/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 14.0; MARKETING_VERSION = 1.1; PRODUCT_BUNDLE_IDENTIFIER = com.xorbitlab.bugger; @@ -412,7 +418,6 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ - }; rootObject = 46F86FAA6BBF9AC94A7E4595 /* Project object */; } diff --git a/Sources/Views/FloatingWidget/FloatingWidgetWindow.swift b/Sources/Views/FloatingWidget/FloatingWidgetWindow.swift index 7d2d6bd..18686f1 100644 --- a/Sources/Views/FloatingWidget/FloatingWidgetWindow.swift +++ b/Sources/Views/FloatingWidget/FloatingWidgetWindow.swift @@ -2,9 +2,12 @@ import AppKit import SwiftUI final class FloatingWidgetWindow: NSPanel { + private let margin: CGFloat = 16 + private let bottomOffset: CGFloat = 200 + init() { super.init( - contentRect: NSRect(x: 0, y: 0, width: 140, height: 70), + contentRect: NSRect(x: 0, y: 0, width: 1, height: 1), styleMask: [.borderless, .nonactivatingPanel], backing: .buffered, defer: false @@ -20,20 +23,63 @@ final class FloatingWidgetWindow: NSPanel { hidesOnDeactivate = false animationBehavior = .none + // Place the 1x1 placeholder in the bottom-right corner so the first + // content measurement anchors to the screen's right edge. if let screen = NSScreen.main { let screenFrame = screen.visibleFrame - setFrameOrigin(NSPoint(x: screenFrame.maxX - 100, y: screenFrame.minY + 200)) + setFrameOrigin(NSPoint( + x: screenFrame.maxX - 1 - margin, + y: screenFrame.minY + bottomOffset + )) } - contentView = NSHostingView(rootView: FloatingWidgetView()) + let rootView = FloatingWidgetView { [weak self] size in + self?.applyContentSize(size) + } + let hostingView = NSHostingView(rootView: rootView) + contentView = hostingView + + // Size to the content's intrinsic size up front to avoid a 1x1 flash + // before the first SwiftUI layout pass reports a measurement. + applyContentSize(hostingView.fittingSize) } override var canBecomeKey: Bool { false } override var canBecomeMain: Bool { false } + + /// Resizes the window to fit its content while keeping the bottom-right + /// corner anchored, so a growing bug count extends leftward instead of + /// spilling off-screen. Clamped to the visible screen frame as a safety + /// net (e.g. when the user has dragged the widget toward an edge). + private func applyContentSize(_ size: CGSize) { + guard size.width > 0, size.height > 0 else { return } + // Skip no-op resizes to avoid a layout feedback loop with SwiftUI. + guard abs(size.width - frame.width) > 0.5 + || abs(size.height - frame.height) > 0.5 else { return } + + var newFrame = frame + // Keep the right edge: grow leftward as the count widens. + newFrame.origin.x = newFrame.maxX - size.width + // Keep the bottom edge: grow upward when the priority row appears. + newFrame.origin.y = newFrame.minY + newFrame.size = size + + if let screen = NSScreen.main { + let visible = screen.visibleFrame + newFrame.origin.x = max(newFrame.origin.x, visible.minX) + newFrame.origin.y = min( + max(newFrame.origin.y, visible.minY), + visible.maxY - size.height + ) + } + + setFrame(newFrame, display: true) + } } struct FloatingWidgetView: View { @State private var bugStore = BugStore.shared + let onSizeChange: (CGSize) -> Void private var priorityCounts: [(BugPriority, Int)] { let active = bugStore.activeBugs @@ -56,6 +102,7 @@ struct FloatingWidgetView: View { Text("\(bugStore.activeBugs.count)") .font(.title3) .fontWeight(.bold) + .monospacedDigit() } if !priorityCounts.isEmpty { HStack(spacing: 6) { @@ -67,6 +114,7 @@ struct FloatingWidgetView: View { Text("\(count)") .font(.caption2) .fontWeight(.medium) + .monospacedDigit() } } } @@ -81,5 +129,17 @@ struct FloatingWidgetView: View { ) } .buttonStyle(.plain) + // Let the button take its intrinsic size so the window can fit it + // exactly, regardless of the (initially 1x1) hosting container. + .fixedSize() + .background( + GeometryReader { proxy in + Color.clear + .onAppear { onSizeChange(proxy.size) } + .onChange(of: proxy.size) { _, newSize in + onSizeChange(newSize) + } + } + ) } }