diff --git a/README.md b/README.md index b36a8ff..19faf71 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -
TechPie logo @@ -78,12 +77,12 @@ export HOS_SDK_HOME="$HOME/dev/command-line-tools/sdk" - macOS - Xcode - CocoaPods -- iOS Deployment Target 13.0 +- iOS Deployment Target 14.0 ### HarmonyOS - Flutter (OHOS patch) 3.27.5-ohos-1.0.5 -- [Huawei Command Tools 6.1.1 Beta1](https://developer.huawei.com/consumer/cn/download/command-line-tools-for-hmos) +- [Huawei Command Tools 6.1.1 Beta1](https://developer.huawei.com/consumer/cn/download/command-line-tools-for-hmos) ## License diff --git a/ios/Podfile b/ios/Podfile index 2dbf7d7..c2c1dc5 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '13.0' +platform :ios, '14.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 112a9bf..ec25b3f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2,6 +2,8 @@ PODS: - Flutter (1.0.0) - flutter_secure_storage (6.0.0): - Flutter + - home_widget (0.0.1): + - Flutter - open_filex (0.0.2): - Flutter - package_info_plus (0.4.5): @@ -21,6 +23,7 @@ PODS: DEPENDENCIES: - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) + - home_widget (from `.symlinks/plugins/home_widget/ios`) - open_filex (from `.symlinks/plugins/open_filex/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) @@ -33,6 +36,8 @@ EXTERNAL SOURCES: :path: Flutter flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" + home_widget: + :path: ".symlinks/plugins/home_widget/ios" open_filex: :path: ".symlinks/plugins/open_filex/ios" package_info_plus: @@ -49,6 +54,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 + home_widget: 54b4f6b36ed8d64cfee594a476225c35c3e45091 open_filex: 432f3cd11432da3e39f47fcc0df2b1603854eff1 package_info_plus: 566e1b7a2f3900e4b0020914ad3fc051dcc95596 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 @@ -56,6 +62,6 @@ SPEC CHECKSUMS: url_launcher_ios: 694010445543906933d732453a59da0a173ae33d webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2 -PODFILE CHECKSUM: 251cb053df7158f337c0712f2ab29f4e0fa474ce +PODFILE CHECKSUM: e30f02f9d1c72c47bb6344a0a748c9d268180865 COCOAPODS: 1.16.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 2d632d9..ae58d88 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -25,11 +25,14 @@ 5A00101E2F1A000100000001 /* NativeTextFieldGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A00101D2F1A000100000001 /* NativeTextFieldGroup.swift */; }; 6BFBE954DB868241E9E9810B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 052EF181B45C1F8AB028A91F /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + AE1A35252FDAC803007C86E7 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE1A35242FDAC803007C86E7 /* WidgetKit.framework */; }; + AE1A35272FDAC803007C86E7 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE1A35262FDAC803007C86E7 /* SwiftUI.framework */; }; + AE1A35382FDAC804007C86E7 /* TechPieWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = AE1A35232FDAC803007C86E7 /* TechPieWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; AE9BB45FC9E1D531003A2DF5 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95DFA3F27C43BF6B489182B8 /* Pods_RunnerTests.framework */; }; - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -40,6 +43,13 @@ remoteGlobalIDString = 97C146ED1CF9000F007C117D; remoteInfo = Runner; }; + AE1A35362FDAC804007C86E7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = AE1A35222FDAC803007C86E7; + remoteInfo = TechPieWidgetExtension; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -53,6 +63,17 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + AE1A35392FDAC804007C86E7 /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + AE1A35382FDAC804007C86E7 /* TechPieWidgetExtension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -80,6 +101,7 @@ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 776CD06E7F9DDAC30B1D93AD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 95DFA3F27C43BF6B489182B8 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; @@ -89,12 +111,41 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AE1A35232FDAC803007C86E7 /* TechPieWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TechPieWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + AE1A35242FDAC803007C86E7 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + AE1A35262FDAC803007C86E7 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + AE1A35412FDAC98F007C86E7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + AE1A35422FDAC9B5007C86E7 /* TechPieWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TechPieWidgetExtension.entitlements; sourceTree = ""; }; C6ECDBC06E9BDB1CBA58B7DB /* 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 = ""; }; C7BBB453CDB9F73A63A4A327 /* 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 = ""; }; D3EC6B66BB17FD8FCFF14373 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + AE1A353D2FDAC804007C86E7 /* Exceptions for "TechPieWidget" folder in "TechPieWidgetExtension" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = AE1A35222FDAC803007C86E7 /* TechPieWidgetExtension */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + AE1A35282FDAC803007C86E7 /* TechPieWidget */ = { + isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + AE1A353D2FDAC804007C86E7 /* Exceptions for "TechPieWidget" folder in "TechPieWidgetExtension" target */, + ); + explicitFileTypes = { + }; + explicitFolders = ( + ); + path = TechPieWidget; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 37EE0E03704066D35E7DAB45 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -113,6 +164,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AE1A35202FDAC803007C86E7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AE1A35272FDAC803007C86E7 /* SwiftUI.framework in Frameworks */, + AE1A35252FDAC803007C86E7 /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -121,6 +181,8 @@ children = ( 052EF181B45C1F8AB028A91F /* Pods_Runner.framework */, 95DFA3F27C43BF6B489182B8 /* Pods_RunnerTests.framework */, + AE1A35242FDAC803007C86E7 /* WidgetKit.framework */, + AE1A35262FDAC803007C86E7 /* SwiftUI.framework */, ); name = Frameworks; sourceTree = ""; @@ -181,8 +243,10 @@ 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( + AE1A35422FDAC9B5007C86E7 /* TechPieWidgetExtension.entitlements */, 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, + AE1A35282FDAC803007C86E7 /* TechPieWidget */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, 1FD71643C385FC3B24A7C891 /* Pods */, @@ -195,6 +259,7 @@ children = ( 97C146EE1CF9000F007C117D /* Runner.app */, 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + AE1A35232FDAC803007C86E7 /* TechPieWidgetExtension.appex */, ); name = Products; sourceTree = ""; @@ -202,6 +267,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + AE1A35412FDAC98F007C86E7 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -238,9 +304,6 @@ productType = "com.apple.product-type.bundle.unit-test"; }; 97C146ED1CF9000F007C117D /* Runner */ = { - packageProductDependencies = ( - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, - ); isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( @@ -250,28 +313,51 @@ 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, + AE1A35392FDAC804007C86E7 /* Embed Foundation Extensions */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 1C676109FBCDA2409F8A534A /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( + AE1A35372FDAC804007C86E7 /* PBXTargetDependency */, ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; + AE1A35222FDAC803007C86E7 /* TechPieWidgetExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = AE1A353E2FDAC804007C86E7 /* Build configuration list for PBXNativeTarget "TechPieWidgetExtension" */; + buildPhases = ( + AE1A351F2FDAC803007C86E7 /* Sources */, + AE1A35202FDAC803007C86E7 /* Frameworks */, + AE1A35212FDAC803007C86E7 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + AE1A35282FDAC803007C86E7 /* TechPieWidget */, + ); + name = TechPieWidgetExtension; + productName = TechPieWidgetExtension; + productReference = AE1A35232FDAC803007C86E7 /* TechPieWidgetExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { - packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, - ); isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 1640; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { @@ -283,6 +369,9 @@ CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; }; + AE1A35222FDAC803007C86E7 = { + CreatedOnToolsVersion = 16.4; + }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; @@ -294,12 +383,16 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, 331C8080294A63A400263BE5 /* RunnerTests */, + AE1A35222FDAC803007C86E7 /* TechPieWidgetExtension */, ); }; /* End PBXProject section */ @@ -323,6 +416,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AE1A35212FDAC803007C86E7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -451,6 +551,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + AE1A351F2FDAC803007C86E7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -459,6 +566,11 @@ target = 97C146ED1CF9000F007C117D /* Runner */; targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; }; + AE1A35372FDAC804007C86E7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = AE1A35222FDAC803007C86E7 /* TechPieWidgetExtension */; + targetProxy = AE1A35362FDAC804007C86E7 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -525,7 +637,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -541,6 +653,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -656,7 +769,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -709,7 +822,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -727,6 +840,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -749,6 +863,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -764,6 +879,123 @@ }; name = Release; }; + AE1A353A2FDAC804007C86E7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + 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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = TechPieWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = TechPieWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = TechPieWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.example.techpie.TechPieWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + AE1A353B2FDAC804007C86E7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + 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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = TechPieWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = TechPieWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = TechPieWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.example.techpie.TechPieWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + AE1A353C2FDAC804007C86E7 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + 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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = TechPieWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = TechPieWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = TechPieWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.example.techpie.TechPieWidget; + 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 */ @@ -797,13 +1029,25 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + AE1A353E2FDAC804007C86E7 /* Build configuration list for PBXNativeTarget "TechPieWidgetExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AE1A353A2FDAC804007C86E7 /* Debug */, + AE1A353B2FDAC804007C86E7 /* Release */, + AE1A353C2FDAC804007C86E7 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ + /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; /* End XCLocalSwiftPackageReference section */ + /* Begin XCSwiftPackageProductDependency section */ 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { isa = XCSwiftPackageProductDependency; diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements new file mode 100644 index 0000000..fbb0586 --- /dev/null +++ b/ios/Runner/Runner.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.com.example.techpie + + + diff --git a/ios/TechPieWidget/Assets.xcassets/AccentColor.colorset/Contents.json b/ios/TechPieWidget/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/ios/TechPieWidget/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/TechPieWidget/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/TechPieWidget/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2305880 --- /dev/null +++ b/ios/TechPieWidget/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,35 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/TechPieWidget/Assets.xcassets/Contents.json b/ios/TechPieWidget/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/ios/TechPieWidget/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/TechPieWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/ios/TechPieWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/ios/TechPieWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/TechPieWidget/Info.plist b/ios/TechPieWidget/Info.plist new file mode 100644 index 0000000..0f118fb --- /dev/null +++ b/ios/TechPieWidget/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/ios/TechPieWidget/TechPieWidget.swift b/ios/TechPieWidget/TechPieWidget.swift new file mode 100644 index 0000000..7704427 --- /dev/null +++ b/ios/TechPieWidget/TechPieWidget.swift @@ -0,0 +1,215 @@ +import WidgetKit +import SwiftUI + +struct Provider: TimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), courses: [], assignments: []) + } + + func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { + let entry = SimpleEntry(date: Date(), + courses: WidgetDataManager.shared.courses, + assignments: WidgetDataManager.shared.assignments) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { + let entry = SimpleEntry(date: Date(), + courses: WidgetDataManager.shared.courses, + assignments: WidgetDataManager.shared.assignments) + + // Update widget occasionally or when told by Flutter + let nextUpdate = Calendar.current.date(byAdding: .minute, value: 30, to: Date()) ?? Date().addingTimeInterval(30 * 60) + let timeline = Timeline(entries: [entry], policy: .after(nextUpdate)) + completion(timeline) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date + let courses: [Course] + let assignments: [Assignment] +} + +struct TechPieWidgetEntryView : View { + var entry: Provider.Entry + @Environment(\.widgetFamily) var family + + var body: some View { + ZStack { + VStack(alignment: .leading, spacing: 10) { + if family == .systemSmall { + smallView + } else { + mediumView + } + } + .padding() + } + } + + var smallView: some View { + VStack(alignment: .leading, spacing: 8) { + HStack { + Image(systemName: "book.fill") + .foregroundColor(.blue) + Text("Next Class") + .font(.headline) + } + + if let firstClass = entry.courses.first { + Text(firstClass.name) + .font(.subheadline) + .fontWeight(.bold) + .lineLimit(2) + Text("\(firstClass.startTime) - \(firstClass.endTime)") + .font(.caption) + .foregroundColor(.secondary) + Text(firstClass.location) + .font(.caption) + .foregroundColor(.secondary) + } else { + Text("No more classes today! 🎉") + .font(.subheadline) + .foregroundColor(.secondary) + } + } + } + + var mediumView: some View { + HStack(alignment: .top, spacing: 16) { + // Left Side: Schedule + VStack(alignment: .leading, spacing: 8) { + HStack { + Image(systemName: "calendar") + .foregroundColor(.blue) + Text("Today's Classes") + .font(.headline) + } + + if entry.courses.isEmpty { + Text("Free day! 🎉") + .font(.subheadline) + .foregroundColor(.secondary) + } else { + ForEach(entry.courses.prefix(2)) { course in + VStack(alignment: .leading, spacing: 2) { + Text(course.name) + .font(.subheadline) + .fontWeight(.medium) + .lineLimit(1) + Text("\(course.startTime) | \(course.location)") + .font(.caption2) + .foregroundColor(.secondary) + } + } + } + } + .frame(maxWidth: .infinity, alignment: .leading) + + Divider() + + // Right Side: Assignments + VStack(alignment: .leading, spacing: 8) { + HStack { + Image(systemName: "doc.text.fill") + .foregroundColor(.orange) + Text("Pending Work") + .font(.headline) + } + + if entry.assignments.isEmpty { + Text("All caught up! ✅") + .font(.subheadline) + .foregroundColor(.secondary) + } else { + ForEach(entry.assignments.prefix(2)) { assignment in + VStack(alignment: .leading, spacing: 2) { + Text(assignment.title) + .font(.subheadline) + .fontWeight(.medium) + .lineLimit(1) + Text(assignment.course) + .font(.caption2) + .foregroundColor(.secondary) + .lineLimit(1) + } + } + } + } + .frame(maxWidth: .infinity, alignment: .leading) + } + } +} + +struct TechPieWidget: Widget { + let kind: String = "TechPieWidget" + + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + if #available(iOS 17.0, *) { + TechPieWidgetEntryView(entry: entry) + .containerBackground(Color(UIColor.systemBackground), for: .widget) + } else { + TechPieWidgetEntryView(entry: entry) + .background(Color(UIColor.systemBackground)) + } + } + .configurationDisplayName("TechPie Tracker") + .description("Track your daily schedule and pending assignments.") + .supportedFamilies([.systemSmall, .systemMedium]) + } +} + +// MARK: - Data Models + +struct Course: Codable, Identifiable { + var id: String { name + startTime } + let name: String + let location: String + let startTime: String + let endTime: String +} + +struct Assignment: Codable, Identifiable { + var id: String { title + course } + let title: String + let course: String + let due: String +} + +class WidgetDataManager { + static let shared = WidgetDataManager() + // IMPORTANT: Match this with your App Group ID configured in Xcode + let appGroupID = "group.com.example.techpie" + + var courses: [Course] { + guard let defaults = UserDefaults(suiteName: appGroupID), + let dataString = defaults.string(forKey: "schedule_data"), + let data = dataString.data(using: .utf8) else { + return [] + } + + do { + return try JSONDecoder().decode([Course].self, from: data) + } catch { + print("Error decoding courses: \(error)") + return [] + } + } + + var assignments: [Assignment] { + guard let defaults = UserDefaults(suiteName: appGroupID), + let dataString = defaults.string(forKey: "assignment_data"), + let data = dataString.data(using: .utf8) else { + return [] + } + + do { + return try JSONDecoder().decode([Assignment].self, from: data) + } catch { + print("Error decoding assignments: \(error)") + return [] + } + } +} diff --git a/ios/TechPieWidget/TechPieWidgetBundle.swift b/ios/TechPieWidget/TechPieWidgetBundle.swift new file mode 100644 index 0000000..64449a7 --- /dev/null +++ b/ios/TechPieWidget/TechPieWidgetBundle.swift @@ -0,0 +1,16 @@ +// +// TechPieWidgetBundle.swift +// TechPieWidget +// +// Created by Henry Li on 2026/6/11. +// + +import WidgetKit +import SwiftUI + +@main +struct TechPieWidgetBundle: WidgetBundle { + var body: some Widget { + TechPieWidget() + } +} diff --git a/ios/TechPieWidgetExtension.entitlements b/ios/TechPieWidgetExtension.entitlements new file mode 100644 index 0000000..fbb0586 --- /dev/null +++ b/ios/TechPieWidgetExtension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.com.example.techpie + + + diff --git a/lib/services/assignment_service.dart b/lib/services/assignment_service.dart index e6430ef..39f23f9 100644 --- a/lib/services/assignment_service.dart +++ b/lib/services/assignment_service.dart @@ -14,6 +14,7 @@ import 'http_client.dart'; import 'schedule_service.dart'; import 'storage_service.dart'; import 'third_party_auth_service.dart'; +import 'widget_sync_service.dart'; class AssignmentService extends ChangeNotifier { final StorageService _storage; @@ -91,6 +92,7 @@ class AssignmentService extends ChangeNotifier { _error = null; await _storage.clearCachedAssignments(); notifyListeners(); + _syncWidget(); } /// Hydrate from local cache so the UI doesn't flash empty on app start @@ -100,17 +102,21 @@ class AssignmentService extends ChangeNotifier { final raw = _storage.loadCachedAssignments(); if (raw.isEmpty) { notifyListeners(); + _syncWidget(); return; } _assignments = raw.map((e) => Assignment.fromJson(e)).toList() ..sort((a, b) => a.due.compareTo(b.due)); + _syncWidget(); notifyListeners(); } // -- Override mutators -- - Future _persistOverrides() => - _storage.saveAssignmentOverrides(_overrides); + Future _persistOverrides() async { + await _storage.saveAssignmentOverrides(_overrides); + _syncWidget(); + } Future setCompleted(Assignment a, bool completed) async { _overrides.completed[AssignmentOverrides.keyFor(a)] = completed; @@ -221,6 +227,7 @@ class AssignmentService extends ChangeNotifier { await _storage.saveCachedAssignments( merged.map((a) => a.toJson()).toList(), ); + _syncWidget(); } catch (e) { _error = '同步失败,请检查网络或稍后重试'; } finally { @@ -289,6 +296,7 @@ class AssignmentService extends ChangeNotifier { await _storage.saveCachedAssignments( merged.map((a) => a.toJson()).toList(), ); + _syncWidget(); } catch (e) { _error = e.toString(); } @@ -567,4 +575,11 @@ class AssignmentService extends ChangeNotifier { ? (baseCookies.isNotEmpty ? '$baseCookies; CASTGC=$tgc' : 'CASTGC=$tgc') : baseCookies; } + + void _syncWidget() { + unawaited( + WidgetSyncService.syncAssignments(_assignments, _overrides) + .catchError((_) {}), + ); + } } diff --git a/lib/services/schedule_service.dart b/lib/services/schedule_service.dart index 8219edf..d3fae9e 100644 --- a/lib/services/schedule_service.dart +++ b/lib/services/schedule_service.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; @@ -8,6 +9,7 @@ import 'api_base_url.dart'; import 'auth_service.dart'; import 'http_client.dart'; import 'storage_service.dart'; +import 'widget_sync_service.dart'; class ScheduleService extends ChangeNotifier { final StorageService _storage; @@ -62,6 +64,7 @@ class ScheduleService extends ChangeNotifier { _courseTable = _storage.loadCourseTable(_selectedSemesterId!); } _termBegin = _storage.loadTermBegin(_selectedSemesterId ?? ''); + _syncWidget(); notifyListeners(); } @@ -128,6 +131,7 @@ class ScheduleService extends ChangeNotifier { data['data'] as Map, ); await _storage.saveCourseTable(semesterId, _courseTable!); + _syncWidget(); notifyListeners(); } @@ -240,4 +244,13 @@ class ScheduleService extends ChangeNotifier { return resp; } + + void _syncWidget() { + if (_courseTable != null) { + unawaited( + WidgetSyncService.syncSchedule(_courseTable!, currentWeek()) + .catchError((_) {}), + ); + } + } } diff --git a/lib/services/widget_sync_service.dart b/lib/services/widget_sync_service.dart new file mode 100644 index 0000000..8e356f0 --- /dev/null +++ b/lib/services/widget_sync_service.dart @@ -0,0 +1,107 @@ +import 'dart:convert'; +import 'dart:io' show Platform; + +import 'package:flutter/foundation.dart'; +import 'package:home_widget/home_widget.dart'; + +import '../models/assignment.dart'; +import '../models/assignment_overrides.dart'; +import '../models/course.dart'; +import '../models/course_table.dart'; + +class WidgetSyncService { + static const String _groupId = 'group.com.example.techpie'; + // IMPORTANT: Ensure this matches the App Group identifier configured in Xcode + + static Future syncSchedule(CourseTable table, int currentWeek) async { + if (kIsWeb || (!Platform.isIOS && !Platform.isAndroid)) return; + + try { + final now = DateTime.now(); + final weekday = now.weekday; // 1 = Mon, 7 = Sun + + // Convert to display courses, filtering for current week + final displayCourses = eamsToDisplayCourses(table.courses, currentWeek); + + // Get today's active courses, sorted by period + final todayCourses = displayCourses + .where((c) => c.dayOfWeek == weekday && !c.isGhost) + .toList(); + todayCourses.sort((a, b) => a.startPeriod.compareTo(b.startPeriod)); + + final periods = table.periods.isNotEmpty + ? table.periods.map((p) => p.toPeriod()).toList() + : defaultPeriods; + + final coursesJson = todayCourses.map((c) { + final startTime = periods + .firstWhere( + (p) => p.number == c.startPeriod, + orElse: () => const Period(number: 0, startTime: '', endTime: ''), + ) + .startTime; + final endTime = periods + .firstWhere( + (p) => p.number == c.endPeriod, + orElse: () => const Period(number: 0, startTime: '', endTime: ''), + ) + .endTime; + return { + 'name': c.name, + 'location': c.location, + 'startTime': startTime, + 'endTime': endTime, + }; + }).toList(); + + await HomeWidget.setAppGroupId(_groupId); + await HomeWidget.saveWidgetData('schedule_data', jsonEncode(coursesJson)); + await HomeWidget.updateWidget( + name: 'TechPieWidget', + iOSName: 'TechPieWidget', + ); + } catch (e) { + // Swallow platform-channel errors to avoid unhandled async exceptions + } + } + + static Future syncAssignments( + List assignments, + AssignmentOverrides overrides, + ) async { + if (kIsWeb || (!Platform.isIOS && !Platform.isAndroid)) return; + + try { + final now = DateTime.now(); + + final pending = assignments.where((a) { + if (overrides.isHidden(a)) return false; + if (overrides.effectiveCompleted(a)) return false; + return a.due.isAfter(now); + }).toList(); + + pending.sort((a, b) => a.due.compareTo(b.due)); + final topPending = pending.take(3).toList(); + + final assignmentsJson = topPending.map((a) { + return { + 'title': a.title, + 'course': a.course, + 'due': a.due.toIso8601String(), + }; + }).toList(); + + await HomeWidget.setAppGroupId(_groupId); + await HomeWidget.saveWidgetData( + 'assignment_data', + jsonEncode(assignmentsJson), + ); + await HomeWidget.updateWidget( + name: 'TechPieWidget', + iOSName: 'TechPieWidget', + ); + } catch (e) { + // Swallow platform-channel errors to avoid unhandled async exceptions + } + } +} diff --git a/pubspec.lock b/pubspec.lock index c6b48fa..baac116 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -217,6 +217,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.2.1" + home_widget: + dependency: "direct main" + description: + name: home_widget + sha256: "7a32f7d6a3afd542126fb0004acba939a41ee57d874172926212774fbce684d3" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.2" http: dependency: "direct main" description: @@ -671,7 +679,7 @@ packages: description: path: "packages/webview_flutter/webview_flutter_android" ref: "br_webview_flutter-v4.13.0_ohos" - resolved-ref: "8d70938aa190eb7d7cd4d66f0d16fddb3c2d03ba" + resolved-ref: cd84e4ca392f666bc728c32c49fb328127058826 url: "https://gitcode.com/openharmony-tpc/flutter_packages.git" source: git version: "4.7.0" @@ -680,7 +688,7 @@ packages: description: path: "packages/webview_flutter/webview_flutter_ohos" ref: "br_webview_flutter-v4.13.0_ohos" - resolved-ref: "8d70938aa190eb7d7cd4d66f0d16fddb3c2d03ba" + resolved-ref: cd84e4ca392f666bc728c32c49fb328127058826 url: "https://gitcode.com/openharmony-tpc/flutter_packages.git" source: git version: "4.7.0" @@ -698,7 +706,7 @@ packages: description: path: "packages/webview_flutter/webview_flutter_wkwebview" ref: "br_webview_flutter-v4.13.0_ohos" - resolved-ref: "8d70938aa190eb7d7cd4d66f0d16fddb3c2d03ba" + resolved-ref: cd84e4ca392f666bc728c32c49fb328127058826 url: "https://gitcode.com/openharmony-tpc/flutter_packages.git" source: git version: "3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index 4cba3ee..d67fa2f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: url: https://gitcode.com/openharmony-sig/fluttertpc_flutter_secure_storage.git path: flutter_secure_storage_ohos ref: br_v9.2.2_ohos + home_widget: 0.9.2 http: ^1.4.0 intl: ^0.20.2 open_filex: ^4.5.0