From 0ee55d48737b82e4abf426b037c0f2be12fdfaac Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Sun, 16 Jul 2023 22:46:32 +0800 Subject: [PATCH] #26 new: ios `home widget` --- ios/Runner.xcodeproj/project.pbxproj | 249 +++++++++++++++++- ios/Runner/Info-Debug.plist | 132 +++++----- ios/StatusWidget/Info.plist | 11 + .../StatusWidget.intentdefinition | 118 +++++++++ ios/StatusWidget/StatusWidget.swift | 207 +++++++++++++++ ios/StatusWidget/StatusWidgetBundle.swift | 16 ++ lib/core/extension/order.dart | 4 +- lib/data/provider/server.dart | 18 +- lib/data/provider/snippet.dart | 2 +- lib/data/res/build_data.dart | 6 +- lib/view/page/server/tab.dart | 7 +- macos/Runner.xcodeproj/project.pbxproj | 12 +- 12 files changed, 683 insertions(+), 99 deletions(-) create mode 100644 ios/StatusWidget/Info.plist create mode 100644 ios/StatusWidget/StatusWidget.intentdefinition create mode 100644 ios/StatusWidget/StatusWidget.swift create mode 100644 ios/StatusWidget/StatusWidgetBundle.swift diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 5b70fbfd..77f5737a 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -13,9 +13,27 @@ 9234EA956D1225D388A01660 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C1EB3935F9285537B0516 /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + E33A3E372A626DCD009744AB /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E33A3E362A626DCD009744AB /* WidgetKit.framework */; }; + E33A3E392A626DCD009744AB /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E33A3E382A626DCD009744AB /* SwiftUI.framework */; }; + E33A3E3C2A626DCE009744AB /* StatusWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A3E3B2A626DCE009744AB /* StatusWidgetBundle.swift */; }; + E33A3E402A626DCE009744AB /* StatusWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A3E3F2A626DCE009744AB /* StatusWidget.swift */; }; + E33A3E432A626DD0009744AB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E33A3E422A626DD0009744AB /* Assets.xcassets */; }; + E33A3E452A626DD0009744AB /* StatusWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E33A3E412A626DCE009744AB /* StatusWidget.intentdefinition */; }; + E33A3E462A626DD0009744AB /* StatusWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E33A3E412A626DCE009744AB /* StatusWidget.intentdefinition */; }; + E33A3E492A626DD0009744AB /* StatusWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E33A3E352A626DCD009744AB /* StatusWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; E3DB67ED2A31FE200027B8CB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E3DB67EB2A31FE200027B8CB /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + E33A3E472A626DD0009744AB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = E33A3E342A626DCD009744AB; + remoteInfo = StatusWidgetExtension; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -27,6 +45,17 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + E33A3E4A2A626DD0009744AB /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + E33A3E492A626DD0009744AB /* StatusWidgetExtension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -46,6 +75,14 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9C5314B89F1F73A1900CCAFD /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; A775F241DEE026555178AC01 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E33A3E352A626DCD009744AB /* StatusWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = StatusWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + E33A3E362A626DCD009744AB /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + E33A3E382A626DCD009744AB /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + E33A3E3B2A626DCE009744AB /* StatusWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusWidgetBundle.swift; sourceTree = ""; }; + E33A3E3F2A626DCE009744AB /* StatusWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusWidget.swift; sourceTree = ""; }; + E33A3E412A626DCE009744AB /* StatusWidget.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = StatusWidget.intentdefinition; sourceTree = ""; }; + E33A3E422A626DD0009744AB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + E33A3E442A626DD0009744AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E398BF6A29BDB34500FE4FD5 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; E3DB67EC2A31FE200027B8CB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXFileReference section */ @@ -59,6 +96,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E33A3E322A626DCD009744AB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E33A3E392A626DCD009744AB /* SwiftUI.framework in Frameworks */, + E33A3E372A626DCD009744AB /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -88,6 +134,7 @@ children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, + E33A3E3A2A626DCE009744AB /* StatusWidget */, 97C146EF1CF9000F007C117D /* Products */, 65C40392B90925608A0465EE /* Pods */, D242A20E381A343934B6A7B6 /* Frameworks */, @@ -98,6 +145,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + E33A3E352A626DCD009744AB /* StatusWidgetExtension.appex */, ); name = Products; sourceTree = ""; @@ -122,10 +170,24 @@ isa = PBXGroup; children = ( 278C1EB3935F9285537B0516 /* Pods_Runner.framework */, + E33A3E362A626DCD009744AB /* WidgetKit.framework */, + E33A3E382A626DCD009744AB /* SwiftUI.framework */, ); name = Frameworks; sourceTree = ""; }; + E33A3E3A2A626DCE009744AB /* StatusWidget */ = { + isa = PBXGroup; + children = ( + E33A3E3B2A626DCE009744AB /* StatusWidgetBundle.swift */, + E33A3E3F2A626DCE009744AB /* StatusWidget.swift */, + E33A3E412A626DCE009744AB /* StatusWidget.intentdefinition */, + E33A3E422A626DD0009744AB /* Assets.xcassets */, + E33A3E442A626DD0009744AB /* Info.plist */, + ); + path = StatusWidget; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -141,22 +203,42 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, AA0A1FF2F3246F84EB0D91F2 /* [CP] Embed Pods Frameworks */, + E33A3E4A2A626DD0009744AB /* Embed Foundation Extensions */, ); buildRules = ( ); dependencies = ( + E33A3E482A626DD0009744AB /* PBXTargetDependency */, ); name = Runner; productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; + E33A3E342A626DCD009744AB /* StatusWidgetExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = E33A3E4E2A626DD0009744AB /* Build configuration list for PBXNativeTarget "StatusWidgetExtension" */; + buildPhases = ( + E33A3E312A626DCD009744AB /* Sources */, + E33A3E322A626DCD009744AB /* Frameworks */, + E33A3E332A626DCD009744AB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = StatusWidgetExtension; + productName = StatusWidgetExtension; + productReference = E33A3E352A626DCD009744AB /* StatusWidgetExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 1430; LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { @@ -164,6 +246,9 @@ CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; }; + E33A3E342A626DCD009744AB = { + CreatedOnToolsVersion = 14.3; + }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; @@ -180,6 +265,7 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + E33A3E342A626DCD009744AB /* StatusWidgetExtension */, ); }; /* End PBXProject section */ @@ -196,6 +282,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E33A3E332A626DCD009744AB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E33A3E432A626DD0009744AB /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -278,11 +372,30 @@ files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + E33A3E462A626DD0009744AB /* StatusWidget.intentdefinition in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E33A3E312A626DCD009744AB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E33A3E402A626DCE009744AB /* StatusWidget.swift in Sources */, + E33A3E452A626DD0009744AB /* StatusWidget.intentdefinition in Sources */, + E33A3E3C2A626DCE009744AB /* StatusWidgetBundle.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + E33A3E482A626DD0009744AB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E33A3E342A626DCD009744AB /* StatusWidgetExtension */; + targetProxy = E33A3E472A626DD0009744AB /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -357,10 +470,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 373; + CURRENT_PROJECT_VERSION = 376; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -368,7 +482,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.373; + MARKETING_VERSION = 1.0.376; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -488,10 +602,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 373; + CURRENT_PROJECT_VERSION = 376; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -499,7 +614,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.373; + MARKETING_VERSION = 1.0.376; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -513,10 +628,11 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 373; + CURRENT_PROJECT_VERSION = 376; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -524,7 +640,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.373; + MARKETING_VERSION = 1.0.376; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -533,6 +649,117 @@ }; name = Release; }; + E33A3E4B2A626DD0009744AB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = BA88US33G6; + GCC_C_LANGUAGE_STANDARD = gnu11; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = StatusWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = StatusWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + E33A3E4C2A626DD0009744AB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = BA88US33G6; + GCC_C_LANGUAGE_STANDARD = gnu11; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = StatusWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = StatusWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + E33A3E4D2A626DD0009744AB /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = BA88US33G6; + GCC_C_LANGUAGE_STANDARD = gnu11; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = StatusWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = StatusWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Profile; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -556,6 +783,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + E33A3E4E2A626DD0009744AB /* Build configuration list for PBXNativeTarget "StatusWidgetExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E33A3E4B2A626DD0009744AB /* Debug */, + E33A3E4C2A626DD0009744AB /* Release */, + E33A3E4D2A626DD0009744AB /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; diff --git a/ios/Runner/Info-Debug.plist b/ios/Runner/Info-Debug.plist index 0de86afe..755f021b 100644 --- a/ios/Runner/Info-Debug.plist +++ b/ios/Runner/Info-Debug.plist @@ -1,68 +1,72 @@ - - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLocalizations - - en - zh - - CFBundleName - ServerBox - CFBundlePackageType - APPL - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - ITSAppUsesNonExemptEncryption - - LSRequiresIPhoneOS - - LSSupportsOpeningDocumentsInPlace - - UIApplicationSupportsIndirectInputEvents - - UIBackgroundModes - - fetch - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIStatusBarHidden - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - NSBonjourServices - - _dartobservatory._tcp - - NSLocalNetworkUsageDescription - ServerBox needs to access your local network to discover and connect to your server. - + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLocalizations + + en + zh + + CFBundleName + ServerBox + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + ITSAppUsesNonExemptEncryption + + LSRequiresIPhoneOS + + LSSupportsOpeningDocumentsInPlace + + NSBonjourServices + + _dartobservatory._tcp + + NSLocalNetworkUsageDescription + ServerBox needs to access your local network to discover and connect to your server. + NSUserActivityTypes + + ConfigurationIntent + + UIApplicationSupportsIndirectInputEvents + + UIBackgroundModes + + fetch + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + diff --git a/ios/StatusWidget/Info.plist b/ios/StatusWidget/Info.plist new file mode 100644 index 00000000..0f118fb7 --- /dev/null +++ b/ios/StatusWidget/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/ios/StatusWidget/StatusWidget.intentdefinition b/ios/StatusWidget/StatusWidget.intentdefinition new file mode 100644 index 00000000..addc6097 --- /dev/null +++ b/ios/StatusWidget/StatusWidget.intentdefinition @@ -0,0 +1,118 @@ + + + + + INEnums + + INIntentDefinitionModelVersion + 1.2 + INIntentDefinitionNamespace + 88xZPY + INIntentDefinitionSystemVersion + 22F82 + INIntentDefinitionToolsBuildVersion + 14E222b + INIntentDefinitionToolsVersion + 14.3 + INIntents + + + INIntentCategory + information + INIntentDescription + Config for home status widget + INIntentDescriptionID + tVvJ9c + INIntentEligibleForWidgets + + INIntentIneligibleForSuggestions + + INIntentLastParameterTag + 2 + INIntentName + Configuration + INIntentParameters + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + Url + INIntentParameterDisplayNameID + 5QiOUM + INIntentParameterDisplayPriority + 1 + INIntentParameterMetadata + + INIntentParameterMetadataCapitalization + Characters + INIntentParameterMetadataDefaultValue + https://push.lolli.tech + INIntentParameterMetadataDefaultValueID + wwvqC2 + INIntentParameterMetadataDisableAutocorrect + + INIntentParameterMetadataDisableSmartDashes + + INIntentParameterMetadataDisableSmartQuotes + + + INIntentParameterName + url + INIntentParameterPromptDialogs + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogType + Configuration + + + INIntentParameterPromptDialogCustom + + INIntentParameterPromptDialogFormatString + Server monitor url + INIntentParameterPromptDialogFormatStringID + j41owf + INIntentParameterPromptDialogType + Primary + + + INIntentParameterSupportsResolution + + INIntentParameterTag + 1 + INIntentParameterType + String + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + + INIntentTitle + StatusWidgetConf + INIntentTitleID + gpCwrM + INIntentType + Custom + INIntentVerb + View + + + INTypes + + + diff --git a/ios/StatusWidget/StatusWidget.swift b/ios/StatusWidget/StatusWidget.swift new file mode 100644 index 00000000..a14ab6ca --- /dev/null +++ b/ios/StatusWidget/StatusWidget.swift @@ -0,0 +1,207 @@ +// +// StatusWidget.swift +// StatusWidget +// +// Created by lolli on 2023/7/15. +// + +import WidgetKit +import SwiftUI +import Intents + +struct Status { + let name: String + let cpu: String + let mem: String + let disk: String + let net: String +} + +let demoStatus = Status(name: "Server Name", cpu: "31.7%", mem: "1.3g / 1.9g", disk: "7.1g / 30.0g", net: "712.3k / 1.2m") +let domain = "com.lollipopkit.toolbox" +var url: String? + +struct Provider: IntentTimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), configuration: ConfigurationIntent(), data: demoStatus, state: .normal) + } + + func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { + let entry = SimpleEntry(date: Date(), configuration: configuration, data: demoStatus, state: .normal) + completion(entry) + } + + func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline) -> ()) { + url = configuration.url + + let currentDate = Date() + let refreshDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)! + StatusLoader.fetch { result in + let entry: SimpleEntry + switch result { + case .success(let status): + entry = SimpleEntry( + date: currentDate, + configuration: configuration, + data: status, + state: .normal + ) + case .failure(let err): + entry = SimpleEntry(date: currentDate, configuration: configuration, data: demoStatus, state: .error(err.localizedDescription)) + } + let timeline = Timeline(entries: [entry], policy: .after(refreshDate)) + completion(timeline) + } + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date + let configuration: ConfigurationIntent + let data: Status + let state: ContentState +} + +struct StatusWidgetEntryView : View { + var entry: Provider.Entry + + var body: some View { + switch entry.state { + case .loading: + ProgressView().padding() + case .error(let descriotion): + Text(descriotion) + case .normal: + VStack(alignment: .leading, spacing: 5.7) { + Text(entry.data.name).font(.system(.title3)) + Spacer() + DetailItem(icon: "cpu", text: entry.data.cpu, color: .primary.opacity(0.7)) + DetailItem(icon: "memorychip", text: entry.data.mem, color: .primary.opacity(0.7)) + DetailItem(icon: "externaldrive", text: entry.data.disk, color: .primary.opacity(0.7)) + Spacer() + DetailItem(icon: "clock", text: date2String(entry.date, dateFormat: "HH:mm"), color: .primary.opacity(0.7)) + }.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .padding() + } + } +} + +struct StatusWidget: Widget { + let kind: String = "StatusWidget" + + var body: some WidgetConfiguration { + IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in + StatusWidgetEntryView(entry: entry) + } + .configurationDisplayName("Status") + .description("Status of your servers.") + .supportedFamilies([.systemSmall]) + } +} + +struct StatusWidget_Previews: PreviewProvider { + static var previews: some View { + StatusWidgetEntryView(entry: SimpleEntry(date: Date(), configuration: ConfigurationIntent(), data: demoStatus, state: .normal)) + .previewContext(WidgetPreviewContext(family: .systemSmall)) + } +} + +struct StatusLoader { + static func fetch(completion: @escaping (Result) -> Void) { + if url == nil || url == "" { + completion(.failure(NSError(domain: domain, code: 1, userInfo: [NSLocalizedDescriptionKey: "Please longpress it to config first."]))) + return + } + let URL = URL(string: url!)! + let task = URLSession.shared.dataTask(with: URL) { (data, response, error) in + guard error == nil else { + completion(.failure(error!)) + return + } + guard data != nil else { + completion(.failure(NSError(domain: domain, code: 2, userInfo: [NSLocalizedDescriptionKey: "empty network data."]))) + return + } + let result = getStatus(fromData: data!) + switch result { + case .success(let status): + completion(.success(status)) + case .failure(let error): + completion(.failure(error)) + } + } + task.resume() + } + + static func getStatus(fromData data: Foundation.Data) -> Result { + + let jsonAll = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any] + let code = jsonAll["code"] as! Int + if (code != 0) { + switch (code) { + default: + let msg = jsonAll["msg"] as! String? ?? "" + return .failure(NSError(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey: msg])) + } + } + + let json = jsonAll["data"] as! [String: Any] + let name = json["name"] as! String + let disk = json["disk"] as! String + let cpu = json["cpu"] as! String + let mem = json["mem"] as! String + let net = json["net"] as! String + return .success(Status(name: name, cpu: cpu, mem: mem, disk: disk, net: net)) + } +} + +private func dynamicUIColor(color: DynamicColor) -> UIColor { + if #available(iOS 13, *) { // 版本号大于等于13 + return UIColor { (traitCollection: UITraitCollection) -> UIColor in + return traitCollection.userInterfaceStyle == UIUserInterfaceStyle.dark ? + color.dark : color.light + } +} + return color.light +} + +struct DynamicColor { + let dark: UIColor + let light: UIColor +} + +let bgColor = DynamicColor(dark: UIColor(.black), light: UIColor(.white)) +let textColor = DynamicColor(dark: UIColor(.white), light: UIColor(.black)) + +private func dynamicColor(color: DynamicColor) -> Color { + return Color.init(dynamicUIColor(color: color)) +} + +struct DetailItem: View { + let icon: String + let text: String + let color: Color + + var body: some View { + HStack(spacing: 5.7) { + Image(systemName: icon).resizable().foregroundColor(color).frame(width: 11, height: 11, alignment: .center) + Text(text) + .font(.system(.caption2)) + .foregroundColor(color) + } + } +} + +func date2String(_ date:Date, dateFormat:String = "yyyy-MM-dd HH:mm:ss") -> String { + let formatter = DateFormatter() + formatter.locale = Locale.init(identifier: "zh_CN") + formatter.dateFormat = dateFormat + let date = formatter.string(from: date) + return date +} + +enum ContentState { + case loading + case error(String) + case normal +} diff --git a/ios/StatusWidget/StatusWidgetBundle.swift b/ios/StatusWidget/StatusWidgetBundle.swift new file mode 100644 index 00000000..0c82f5ab --- /dev/null +++ b/ios/StatusWidget/StatusWidgetBundle.swift @@ -0,0 +1,16 @@ +// +// StatusWidgetBundle.swift +// StatusWidget +// +// Created by lolli on 2023/7/15. +// + +import WidgetKit +import SwiftUI + +@main +struct StatusWidgetBundle: WidgetBundle { + var body: some Widget { + StatusWidget() + } +} diff --git a/lib/core/extension/order.dart b/lib/core/extension/order.dart index c94615dd..474885c8 100644 --- a/lib/core/extension/order.dart +++ b/lib/core/extension/order.dart @@ -53,8 +53,8 @@ extension OrderX on Order { } /// order: ['d', 'b', 'e']\ - /// items: ['a', 'b', 'c', 'd']\ - /// result: ['b', 'd', 'a', 'c']\ + /// this: ['a', 'b', 'c', 'd']\ + /// result: ['d', 'b', 'a', 'c']\ /// return: ['e'] List reorder({ required List order, diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index f1d0580c..2e304b3c 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -45,22 +45,14 @@ class ServerProvider extends BusyProvider { } final serverOrder_ = _settingStore.serverOrder.fetch(); if (serverOrder_ != null) { - _serverOrder.addAll(serverOrder_.toSet()); - if (_serverOrder.length != spis.length) { - final missed = spis - .where( - (e) => !_serverOrder.contains(e.id), - ) - .map((e) => e.id); - _serverOrder.addAll(missed); - } + spis.reorder( + order: serverOrder_, + finder: (n, id) => n.id == id, + ); + _serverOrder.addAll(spis.map((e) => e.id)); } else { _serverOrder.addAll(_servers.keys); } - final surplus = _serverOrder.where( - (e) => !_servers.containsKey(e), - ); - _serverOrder.removeWhere((element) => surplus.contains(element)); _settingStore.serverOrder.put(_serverOrder); _updateTags(); setBusyState(false); diff --git a/lib/data/provider/snippet.dart b/lib/data/provider/snippet.dart index 3f2ed7b2..8240713d 100644 --- a/lib/data/provider/snippet.dart +++ b/lib/data/provider/snippet.dart @@ -24,7 +24,7 @@ class SnippetProvider extends BusyProvider { if (order != null) { final surplus = _snippets.reorder( order: order, - finder: (order, name) => order.name == name, + finder: (n, name) => n.name == name, ); order.removeWhere((e) => surplus.any((ele) => ele == e)); _setting.snippetOrder.put(order); diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 29004165..57702af3 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,8 +2,8 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 375; + static const int build = 376; static const String engine = "3.10.5"; - static const String buildAt = "2023-07-08 14:54:40.994903"; - static const int modifications = 12; + static const String buildAt = "2023-07-08 15:09:08.542818"; + static const int modifications = 2; } diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index f8fbde9f..f60fe623 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -126,10 +126,9 @@ class _ServerPageState extends State ); }), itemBuilder: (_, index) => FadeIn( - key: ValueKey('$_tag${filtered[index]}'), - child: _buildEachServerCard( - pro.servers[filtered[index]], - )), + key: ValueKey('$_tag${filtered[index]}'), + child: _buildEachServerCard(pro.servers[filtered[index]]), + ), itemCount: filtered.length, ); }, diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 73abda91..b457ebf6 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -475,9 +475,9 @@ baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 373; + CURRENT_PROJECT_VERSION = 376; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.373; + MARKETING_VERSION = 1.0.376; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -490,9 +490,9 @@ baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 373; + CURRENT_PROJECT_VERSION = 376; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.373; + MARKETING_VERSION = 1.0.376; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -505,9 +505,9 @@ baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 373; + CURRENT_PROJECT_VERSION = 376; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0.373; + MARKETING_VERSION = 1.0.376; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0;