diff --git a/experimental/date_planner/.gitignore b/experimental/date_planner/.gitignore
new file mode 100644
index 000000000..29a3a5017
--- /dev/null
+++ b/experimental/date_planner/.gitignore
@@ -0,0 +1,43 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/experimental/date_planner/.metadata b/experimental/date_planner/.metadata
new file mode 100644
index 000000000..eeac26e64
--- /dev/null
+++ b/experimental/date_planner/.metadata
@@ -0,0 +1,30 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ - platform: ios
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/experimental/date_planner/README.md b/experimental/date_planner/README.md
new file mode 100644
index 000000000..d28251c75
--- /dev/null
+++ b/experimental/date_planner/README.md
@@ -0,0 +1,3 @@
+An in-progress exploration of an iOS-style Date Planner app,
+similar to the SwiftUI Tutorial app
+[Date Planner](https://developer.apple.com/tutorials/sample-apps/dateplanner).
diff --git a/experimental/date_planner/analysis_options.yaml b/experimental/date_planner/analysis_options.yaml
new file mode 100644
index 000000000..0d2902135
--- /dev/null
+++ b/experimental/date_planner/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/experimental/date_planner/ios/.gitignore b/experimental/date_planner/ios/.gitignore
new file mode 100644
index 000000000..7a7f9873a
--- /dev/null
+++ b/experimental/date_planner/ios/.gitignore
@@ -0,0 +1,34 @@
+**/dgph
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/experimental/date_planner/ios/Flutter/AppFrameworkInfo.plist b/experimental/date_planner/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 000000000..7c5696400
--- /dev/null
+++ b/experimental/date_planner/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ MinimumOSVersion
+ 12.0
+
+
diff --git a/experimental/date_planner/ios/Flutter/Debug.xcconfig b/experimental/date_planner/ios/Flutter/Debug.xcconfig
new file mode 100644
index 000000000..592ceee85
--- /dev/null
+++ b/experimental/date_planner/ios/Flutter/Debug.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/experimental/date_planner/ios/Flutter/Release.xcconfig b/experimental/date_planner/ios/Flutter/Release.xcconfig
new file mode 100644
index 000000000..592ceee85
--- /dev/null
+++ b/experimental/date_planner/ios/Flutter/Release.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/experimental/date_planner/ios/Runner.xcodeproj/project.pbxproj b/experimental/date_planner/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..a07b33e44
--- /dev/null
+++ b/experimental/date_planner/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,619 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 54;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 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 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97C146ED1CF9000F007C117D;
+ remoteInfo = Runner;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 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 = ""; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 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 = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 331C8082294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXGroup;
+ children = (
+ 331C807B294A618700263BE5 /* RunnerTests.swift */,
+ );
+ path = RunnerTests;
+ sourceTree = "";
+ };
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ 331C8082294A63A400263BE5 /* RunnerTests */,
+ );
+ sourceTree = "";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 331C8080294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+ buildPhases = (
+ 331C807D294A63A400263BE5 /* Sources */,
+ 331C807F294A63A400263BE5 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */,
+ );
+ name = RunnerTests;
+ productName = RunnerTests;
+ productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = YES;
+ LastUpgradeCheck = 1510;
+ ORGANIZATIONNAME = "";
+ TargetAttributes = {
+ 331C8080294A63A400263BE5 = {
+ CreatedOnToolsVersion = 14.0;
+ TestTargetID = 97C146ED1CF9000F007C117D;
+ };
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ LastSwiftMigration = 1100;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ 331C8080294A63A400263BE5 /* RunnerTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 331C807F294A63A400263BE5 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 331C807D294A63A400263BE5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97C146ED1CF9000F007C117D /* Runner */;
+ targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = GAD6HE5MEM;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.datePlanner;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 331C8088294A63A400263BE5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.datePlanner.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Debug;
+ };
+ 331C8089294A63A400263BE5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.datePlanner.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Release;
+ };
+ 331C808A294A63A400263BE5 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.datePlanner.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Profile;
+ };
+ 97C147031CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 97C147041CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 97C147061CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = GAD6HE5MEM;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.datePlanner;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 97C147071CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = GAD6HE5MEM;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.datePlanner;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 331C8088294A63A400263BE5 /* Debug */,
+ 331C8089294A63A400263BE5 /* Release */,
+ 331C808A294A63A400263BE5 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug */,
+ 97C147041CF9000F007C117D /* Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug */,
+ 97C147071CF9000F007C117D /* Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 000000000..919434a62
--- /dev/null
+++ b/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 000000000..18d981003
--- /dev/null
+++ b/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 000000000..f9b0d7c5e
--- /dev/null
+++ b/experimental/date_planner/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/experimental/date_planner/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/experimental/date_planner/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 000000000..8e3ca5dfe
--- /dev/null
+++ b/experimental/date_planner/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/experimental/date_planner/ios/Runner.xcworkspace/contents.xcworkspacedata b/experimental/date_planner/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 000000000..1d526a16e
--- /dev/null
+++ b/experimental/date_planner/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/experimental/date_planner/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/experimental/date_planner/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 000000000..18d981003
--- /dev/null
+++ b/experimental/date_planner/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/experimental/date_planner/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/experimental/date_planner/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 000000000..f9b0d7c5e
--- /dev/null
+++ b/experimental/date_planner/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/experimental/date_planner/ios/Runner/AppDelegate.swift b/experimental/date_planner/ios/Runner/AppDelegate.swift
new file mode 100644
index 000000000..626664468
--- /dev/null
+++ b/experimental/date_planner/ios/Runner/AppDelegate.swift
@@ -0,0 +1,13 @@
+import Flutter
+import UIKit
+
+@main
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+}
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 000000000..d36b1fab2
--- /dev/null
+++ b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+ "images" : [
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-83.5x83.5@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "Icon-App-1024x1024@1x.png",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 000000000..dc9ada472
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 000000000..7353c41ec
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 000000000..797d452e4
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 000000000..6ed2d933e
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 000000000..4cd7b0099
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 000000000..fe730945a
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 000000000..321773cd8
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 000000000..797d452e4
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 000000000..502f463a9
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 000000000..0ec303439
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 000000000..0ec303439
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 000000000..e9f5fea27
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 000000000..84ac32ae7
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 000000000..8953cba09
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 000000000..0467bf12a
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 000000000..0bedcf2fd
--- /dev/null
+++ b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 000000000..9da19eaca
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 000000000..9da19eaca
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 000000000..9da19eaca
Binary files /dev/null and b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 000000000..89c2725b7
--- /dev/null
+++ b/experimental/date_planner/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/experimental/date_planner/ios/Runner/Base.lproj/LaunchScreen.storyboard b/experimental/date_planner/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 000000000..f2e259c7c
--- /dev/null
+++ b/experimental/date_planner/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/experimental/date_planner/ios/Runner/Base.lproj/Main.storyboard b/experimental/date_planner/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 000000000..f3c28516f
--- /dev/null
+++ b/experimental/date_planner/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/experimental/date_planner/ios/Runner/Info.plist b/experimental/date_planner/ios/Runner/Info.plist
new file mode 100644
index 000000000..c836cd5dd
--- /dev/null
+++ b/experimental/date_planner/ios/Runner/Info.plist
@@ -0,0 +1,49 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Date Planner
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ date_planner
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSupportsIndirectInputEvents
+
+
+
diff --git a/experimental/date_planner/ios/Runner/Runner-Bridging-Header.h b/experimental/date_planner/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 000000000..308a2a560
--- /dev/null
+++ b/experimental/date_planner/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/experimental/date_planner/ios/RunnerTests/RunnerTests.swift b/experimental/date_planner/ios/RunnerTests/RunnerTests.swift
new file mode 100644
index 000000000..86a7c3b1b
--- /dev/null
+++ b/experimental/date_planner/ios/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+ func testExample() {
+ // If you add code to the Runner application, consider adding tests here.
+ // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+ }
+
+}
diff --git a/experimental/date_planner/lib/color_options.dart b/experimental/date_planner/lib/color_options.dart
new file mode 100644
index 000000000..9d13e5816
--- /dev/null
+++ b/experimental/date_planner/lib/color_options.dart
@@ -0,0 +1,28 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:math';
+
+import 'package:flutter/cupertino.dart';
+
+enum ColorOptions {
+ primary(CupertinoColors.black),
+ gray(CupertinoColors.lightBackgroundGray),
+ red(CupertinoColors.systemRed),
+ orange(CupertinoColors.systemOrange),
+ yellow(CupertinoColors.systemYellow),
+ green(CupertinoColors.systemGreen),
+ mint(CupertinoColors.systemMint),
+ cyan(CupertinoColors.systemCyan),
+ indigo(CupertinoColors.systemIndigo),
+ purple(CupertinoColors.systemPurple);
+
+ final Color color;
+ static final _rnd = Random();
+
+ const ColorOptions(this.color);
+
+ factory ColorOptions.random() =>
+ ColorOptions.values[_rnd.nextInt(ColorOptions.values.length)];
+}
diff --git a/experimental/date_planner/lib/event.dart b/experimental/date_planner/lib/event.dart
new file mode 100644
index 000000000..1e3b05d0f
--- /dev/null
+++ b/experimental/date_planner/lib/event.dart
@@ -0,0 +1,80 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+import 'package:intl/intl.dart';
+import 'package:uuid/uuid.dart';
+
+import 'color_options.dart';
+import 'event_task.dart';
+
+class Event implements Comparable {
+ static const _uuid = Uuid();
+
+ final id = _uuid.v4();
+ String title;
+ ColorOptions color;
+ IconData icon;
+ List tasks;
+ DateTime date;
+
+ Event({
+ required this.title,
+ ColorOptions? color,
+ this.icon = CupertinoIcons.add,
+ List? tasks,
+ DateTime? date,
+ }) : color = color ?? ColorOptions.random(),
+ tasks = tasks ?? [EventTask(text: '')],
+ date = date ?? DateTime.now();
+
+ Event copy() {
+ return Event(
+ title: title,
+ color: color,
+ icon: icon,
+ tasks: tasks,
+ date: date,
+ );
+ }
+
+ updateWith(Event e) {
+ title = e.title;
+ color = e.color;
+ icon = e.icon;
+ tasks = e.tasks;
+ date = e.date;
+ }
+
+ int get remainingTaskCount => tasks.where((e) => !e.isCompleted).length;
+
+ bool get isComplete => remainingTaskCount == 0;
+
+ bool get isPast => DateTime.now().isAfter(date);
+
+ bool get isWithinSevenDays => !isPast && date.isBefore(FromNow.sevenDays);
+
+ bool get isWithinSevenToThirtyDays =>
+ !isPast && !isWithinSevenDays && date.isBefore(FromNow.thirtyDays);
+
+ bool get isDistant => date.isAfter(FromNow.thirtyDays);
+
+ String get dateFormated => '${DateFormat.yMMMd().format(date)} at '
+ '${DateFormat.Hm().format(date)}';
+
+ @override
+ int compareTo(Event other) => date.compareTo(other.date);
+}
+
+class FromNow {
+ static DateTime get sevenDays => DateTime.now().add(const Duration(days: 7));
+
+ static DateTime get thirtyDays =>
+ DateTime.now().add(const Duration(days: 30));
+
+ static DateTime roundedHours(int hours) {
+ final date = DateTime.now().add(Duration(hours: hours));
+ return DateTime(date.year, date.month, date.day, date.hour);
+ }
+}
diff --git a/experimental/date_planner/lib/event_data.dart b/experimental/date_planner/lib/event_data.dart
new file mode 100644
index 000000000..a3e16fa2c
--- /dev/null
+++ b/experimental/date_planner/lib/event_data.dart
@@ -0,0 +1,162 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+
+import 'color_options.dart';
+import 'event.dart';
+import 'event_task.dart';
+
+class EventData with ChangeNotifier {
+ static final _events = buildSampleData();
+
+ void add(Event event) {
+ _events.add(event);
+ notifyListeners();
+ }
+
+ void delete(Event event) {
+ _events.remove(event);
+ notifyListeners();
+ }
+
+ void update(Event original, Event updated) {
+ _events.firstWhere((e) => e.id == original.id).updateWith(updated);
+ notifyListeners();
+ }
+
+ void exists(Event event) => _events.contains(event);
+
+ List sorted(Period period) => _events
+ .where(
+ (e) => switch (period) {
+ Period.nextSevenDays => e.isWithinSevenDays,
+ Period.nextThirtyDays => e.isWithinSevenToThirtyDays,
+ Period.past => e.isPast,
+ Period.future => e.isDistant,
+ },
+ )
+ .toList()
+ ..sort((e1, e2) => e1.date.compareTo(e2.date));
+}
+
+enum Period {
+ nextSevenDays(name: 'Next 7 Days'),
+ nextThirtyDays(name: 'Next 30 Days'),
+ future(name: 'Future'),
+ past(name: 'Past');
+
+ const Period({required this.name});
+
+ final String name;
+}
+
+List buildSampleData() {
+ return [
+ Event(
+ title: 'Maya\'s Birthday',
+ color: ColorOptions.red,
+ icon: CupertinoIcons.gift,
+ tasks: EventTask.buildList([
+ 'Guava kombucha',
+ 'Paper cups and plates',
+ 'Cheese plate',
+ 'Party poppers',
+ ]),
+ date: FromNow.roundedHours(24 * 30),
+ ),
+ Event(
+ title: 'Pagliacci',
+ color: ColorOptions.yellow,
+ // TODO(mit-mit): Use the icon "theatermasks.fill".
+ icon: CupertinoIcons.thermometer_snowflake,
+ tasks: EventTask.buildList([
+ 'Buy new tux',
+ 'Get tickets',
+ 'Pick up Carmen at the airport and bring her to the show',
+ ]),
+ date: FromNow.roundedHours(22),
+ ),
+ Event(
+ title: 'Doctor\'s Appointment',
+ // TODO(mit-mit): Use the icon "facemask.fill".
+ icon: CupertinoIcons.lab_flask_solid,
+ color: ColorOptions.indigo,
+ tasks:
+ EventTask.buildList(['Bring medical ID', 'Record heart rate data']),
+ date: FromNow.roundedHours(24 * 4),
+ ),
+ Event(
+ title: 'Camping Trip',
+ // TODO(mit-mit): Use the icon "leaf.fill".
+ icon: CupertinoIcons.leaf_arrow_circlepath,
+ color: ColorOptions.green,
+ tasks: EventTask.buildList([
+ 'Find a sleeping bag',
+ 'Bug spray',
+ 'Paper towels',
+ 'Food for 4 meals',
+ 'Straw hat',
+ ]),
+ date: FromNow.roundedHours(36),
+ ),
+ Event(
+ title: 'Game Night',
+ icon: CupertinoIcons.gamecontroller_fill,
+ color: ColorOptions.cyan,
+ tasks: EventTask.buildList([
+ 'Find a board game to bring',
+ 'Bring a desert to share',
+ ]),
+ date: FromNow.roundedHours(24 * 2),
+ ),
+ Event(
+ title: 'First Day of School',
+ // TODO(mit-mit): Use the icon "graduationcap.fill".
+ icon: CupertinoIcons.hammer,
+ color: ColorOptions.primary,
+ tasks: EventTask.buildList([
+ 'Notebooks',
+ 'Pencils',
+ 'Binder',
+ 'First day of school outfit',
+ ]),
+ date: FromNow.roundedHours(24 * 365),
+ ),
+ Event(
+ title: 'Book Launch',
+ icon: CupertinoIcons.book_fill,
+ color: ColorOptions.purple,
+ tasks: EventTask.buildList([
+ 'Finish first draft',
+ 'Send draft to editor',
+ 'Final read-through',
+ ]),
+ date: FromNow.roundedHours(24 * 365 * 2),
+ ),
+ Event(
+ title: 'WWDC',
+ // TODO(mit-mit): Use the icon "globe.americas.fill"
+ icon: CupertinoIcons.globe,
+ color: ColorOptions.gray,
+ tasks: EventTask.buildList([
+ 'Watch Keynote',
+ 'Watch What\'s new in SwiftUI',
+ 'Go to DT developer labs',
+ 'Learn about Create ML',
+ ]),
+ date: DateTime(7, 6, 2021)),
+ Event(
+ title: 'Sayulita Trip',
+ icon: CupertinoIcons.briefcase_fill,
+ color: ColorOptions.orange,
+ tasks: EventTask.buildList([
+ 'Buy plane tickets',
+ 'Get a new bathing suit',
+ 'Find a hotel room',
+ ]),
+ date: FromNow.roundedHours(24 * 19),
+ ),
+ ];
+}
diff --git a/experimental/date_planner/lib/event_detail.dart b/experimental/date_planner/lib/event_detail.dart
new file mode 100644
index 000000000..af27df96f
--- /dev/null
+++ b/experimental/date_planner/lib/event_detail.dart
@@ -0,0 +1,157 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+
+import 'color_options.dart';
+import 'event.dart';
+import 'event_task.dart';
+import 'symbol_editor.dart';
+import 'task_row.dart';
+
+class EventDetail extends StatefulWidget {
+ final Event event;
+ final bool isEditing;
+
+ const EventDetail({
+ super.key,
+ required this.event,
+ required this.isEditing,
+ });
+
+ @override
+ State createState() => _EventDetailState();
+}
+
+class _EventDetailState extends State {
+ final _eventText = TextEditingController();
+
+ @override
+ void initState() {
+ _eventText.text = widget.event.title;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ const titleStyle = TextStyle(fontWeight: FontWeight.bold, fontSize: 22);
+ final event = widget.event;
+
+ // TODO(mit-mit): Investigate manual overriding of colors and padding.
+ return Padding(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ children: [
+ Container(
+ padding: const EdgeInsets.fromLTRB(16, 8, 0, 0),
+ color: CupertinoColors.systemBackground,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ if (widget.isEditing)
+ CupertinoButton(
+ padding: EdgeInsets.zero,
+ minSize: 0,
+ onPressed: () {
+ Navigator.of(context)
+ .push(
+ CupertinoPageRoute<(IconData, ColorOptions)?>(
+ builder: (_) => SymbolEditor(
+ event.icon,
+ event.color,
+ ),
+ ),
+ )
+ .then(
+ ((IconData, ColorOptions)? data) {
+ if (data != null) {
+ setState(() {
+ var (icon, color) = data;
+ event.icon = icon;
+ event.color = color;
+ });
+ }
+ },
+ );
+ },
+ child: Icon(
+ event.icon,
+ size: 28,
+ color: event.color.color,
+ ),
+ ),
+ if (!widget.isEditing)
+ Icon(
+ event.icon,
+ size: 28,
+ color: event.color.color,
+ ),
+ const SizedBox(width: 12),
+ if (widget.isEditing)
+ Expanded(
+ child: CupertinoTextField(
+ decoration: null,
+ padding: EdgeInsets.zero,
+ style: titleStyle,
+ controller: _eventText,
+ onChanged: (value) => event.title = value,
+ ),
+ ),
+ if (!widget.isEditing) Text(event.title, style: titleStyle),
+ ],
+ ),
+ const SizedBox(height: 12),
+ // TODO(mit-mit): Use a widget for picking a date.
+ // Issue: Blocked on not having the right calendar widget:
+ // https://github.com/flutter/flutter/issues/63693
+ Text(event.dateFormated),
+ CupertinoListSection(
+ // TODO(mit-mit): The list of tasks should be left-flush with the date above.
+ margin: EdgeInsets.zero,
+ backgroundColor: CupertinoColors.systemBackground,
+ decoration: null,
+ header: const Text(
+ 'Tasks',
+ style: TextStyle(
+ color: CupertinoColors.black,
+ fontWeight: FontWeight.bold,
+ fontSize: 16,
+ ),
+ ),
+ children: [
+ for (EventTask t in event.tasks)
+ TaskRow(
+ task: t,
+ isEditing: widget.isEditing,
+ ),
+ if (widget.isEditing)
+ // TODO(mit-mit): CupertinoButton with icon support?
+ // Consider if CupertinoButton could support setting
+ // both a label and an icon directly:
+ // https://www.kodeco.com/books/swiftui-cookbook/v1.0/chapters/8-add-an-icon-to-a-button-in-swiftui
+ CupertinoButton(
+ child: const Row(
+ children: [
+ Icon(CupertinoIcons.plus),
+ Text('Add task'),
+ ],
+ ),
+ onPressed: () {
+ setState(() {
+ event.tasks.add(EventTask(text: ''));
+ });
+ },
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/experimental/date_planner/lib/event_editor.dart b/experimental/date_planner/lib/event_editor.dart
new file mode 100644
index 000000000..7b43da359
--- /dev/null
+++ b/experimental/date_planner/lib/event_editor.dart
@@ -0,0 +1,117 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+
+import 'event.dart';
+import 'event_detail.dart';
+
+class EventEditor extends StatefulWidget {
+ final Event event;
+ final bool isNew;
+ const EventEditor({
+ super.key,
+ required this.event,
+ required this.isNew,
+ });
+
+ @override
+ State createState() => _EventEditorState();
+}
+
+class _EventEditorState extends State {
+ late Event event;
+ late bool isNew;
+ late bool isEditing;
+
+ @override
+ void initState() {
+ isNew = widget.isNew;
+ isEditing = isNew;
+ event = widget.event;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return CupertinoPageScaffold(
+ backgroundColor: CupertinoColors.secondarySystemBackground,
+ navigationBar: CupertinoNavigationBar(
+ // TODO(mit-mit): Resolve manual padding issues.
+ //
+ // Note that even with the padding overriding below, the chevron/
+ // back arrow doesn't seem to be far enough to the left.
+ //
+ // Is this maybe the issue here?
+ // https://github.com/flutter/flutter/issues/91715
+ leading: isNew
+ ? CupertinoButton(
+ padding: EdgeInsets.zero,
+ child: const Text('Cancel'),
+ onPressed: () => Navigator.pop(context, null),
+ )
+ : CupertinoButton(
+ padding: EdgeInsets.zero,
+ onPressed: () {
+ Navigator.pop(context, event);
+ },
+ child: const Row(
+ children: [
+ Icon(CupertinoIcons.back),
+ Text('Date Planner'),
+ ],
+ ),
+ ),
+ trailing: CupertinoButton(
+ padding: EdgeInsets.zero,
+ child: Text(isNew ? 'Add' : (isEditing ? 'Done' : 'Edit')),
+ onPressed: () {
+ if (isNew) {
+ Navigator.pop(context, event);
+ } else {
+ setState(() {
+ if (isEditing) {
+ isEditing = false;
+ } else {
+ isEditing = true;
+ }
+ });
+ }
+ },
+ ),
+ ),
+ // TODO(mit-mit): Why isn't SafeArea included by default?
+ child: SafeArea(
+ bottom: false,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ EventDetail(
+ event: event,
+ isEditing: isEditing,
+ ),
+ const Spacer(),
+ if (isEditing && !isNew)
+ ColoredBox(
+ color: CupertinoColors.white,
+ child: Column(
+ children: [
+ CupertinoButton(
+ child: const Text('Delete Event'),
+ onPressed: () {
+ setState(() {
+ Navigator.pop(context, null);
+ });
+ },
+ ),
+ const SizedBox(height: 24),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/experimental/date_planner/lib/event_list.dart b/experimental/date_planner/lib/event_list.dart
new file mode 100644
index 000000000..5289138dd
--- /dev/null
+++ b/experimental/date_planner/lib/event_list.dart
@@ -0,0 +1,99 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+import 'package:provider/provider.dart';
+
+import 'event.dart';
+import 'event_data.dart';
+import 'event_editor.dart';
+import 'event_row.dart';
+
+class EventList extends StatelessWidget {
+ const EventList({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Consumer(
+ builder: (BuildContext context, EventData events, Widget? child) {
+ return CupertinoPageScaffold(
+ // TODO(mit-mit): Avoid having to pass nav bar manually.
+ //
+ // Would like to pass nav bar and body to CupertinoPageScaffold
+ // directly, similar to the Material Scaffold's `appBar` and `body`
+ // args.
+ // https://github.com/flutter/flutter/issues/149625
+ child: CustomScrollView(
+ slivers: [
+ CupertinoSliverNavigationBar(
+ largeTitle: const Text('Date Planner'),
+ trailing: CupertinoButton(
+ padding: EdgeInsets.zero,
+ child: const Icon(CupertinoIcons.plus),
+ onPressed: () async {
+ // Issue: Should go to a sheet, not a a full-screen page.
+ // Blocked on https://github.com/flutter/flutter/issues/42560.
+ Event? newEvent = await Navigator.of(context).push(
+ CupertinoPageRoute(
+ builder: (_) => EventEditor(
+ event: Event(title: 'New event'),
+ isNew: true,
+ ),
+ ),
+ );
+
+ if (newEvent != null) {
+ events.add(newEvent);
+ }
+ },
+ ),
+ ),
+ SliverList.list(
+ children: [
+ for (Period p in Period.values)
+ CupertinoListSection(
+ header: Text(
+ p.name.toUpperCase(),
+ style: const TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 16,
+ ),
+ ),
+ children: [
+ for (Event e in events.sorted(p))
+ // TODO: Support swipe action for deleting.
+ // Should probably use Dismissable?
+ // https://api.flutter.dev/flutter/widgets/Dismissible-class.html
+ EventRow(
+ event: e,
+ onTap: () async {
+ Event? updatedEvent =
+ await Navigator.of(context).push(
+ CupertinoPageRoute(
+ builder: (_) => EventEditor(
+ event: e.copy(),
+ isNew: false,
+ ),
+ ),
+ );
+ if (updatedEvent == null) {
+ // The editor passes back null when it deleted
+ // the element.
+ events.delete(e);
+ } else {
+ events.update(e, updatedEvent);
+ }
+ },
+ )
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/experimental/date_planner/lib/event_row.dart b/experimental/date_planner/lib/event_row.dart
new file mode 100644
index 000000000..4d7c45b88
--- /dev/null
+++ b/experimental/date_planner/lib/event_row.dart
@@ -0,0 +1,52 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter/cupertino.dart';
+
+import 'event.dart';
+
+class EventRow extends StatelessWidget {
+ const EventRow({
+ super.key,
+ required this.event,
+ this.onTap,
+ });
+
+ final Event event;
+ final FutureOr Function()? onTap;
+
+ @override
+ Widget build(BuildContext context) {
+ // TODO(mit-mit): The corners of the tiles should be rounded.
+ return Padding(
+ padding: const EdgeInsets.symmetric(vertical: 4),
+ child: CupertinoListTile(
+ title: Text(
+ event.title,
+ style: const TextStyle(fontWeight: FontWeight.bold),
+ ),
+ subtitle: Text(event.dateFormated),
+ leading: Icon(
+ event.icon,
+ size: 28,
+ color: event.color.color,
+ ),
+ trailing: Row(
+ children: [
+ event.isComplete
+ ? const Icon(CupertinoIcons.check_mark)
+ : Text(
+ '${event.remainingTaskCount}',
+ style: const TextStyle(color: CupertinoColors.systemGrey),
+ ),
+ const CupertinoListTileChevron(),
+ ],
+ ),
+ onTap: onTap,
+ ),
+ );
+ }
+}
diff --git a/experimental/date_planner/lib/event_symbol.dart b/experimental/date_planner/lib/event_symbol.dart
new file mode 100644
index 000000000..fa2187243
--- /dev/null
+++ b/experimental/date_planner/lib/event_symbol.dart
@@ -0,0 +1,58 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+
+// TODO(mit-mit): Update when missing icons are added.
+// https://github.com/flutter/flutter/issues/82634
+final eventSymbols = [
+ CupertinoIcons.house_fill,
+ CupertinoIcons.ticket_fill,
+ CupertinoIcons.gamecontroller_fill,
+//CupertinoIcons.theatermasks_fill,
+//CupertinoIcons.ladybug_fill,
+//CupertinoIcons.books.vertical_fill,
+//CupertinoIcons.moon.zzz_fill,
+ CupertinoIcons.umbrella_fill,
+//CupertinoIcons.paintbrush.pointed_fill,
+//CupertinoIcons.leaf_fill,
+//CupertinoIcons.globe.americas_fill,
+ CupertinoIcons.clock_fill,
+//CupertinoIcons.building.2_fill,
+ CupertinoIcons.gift_fill,
+//CupertinoIcons.graduationcap_fill,
+//CupertinoIcons.heart.rectangle_fill,
+//CupertinoIcons.phone.bubble.left_fill,
+//CupertinoIcons.cloud.rain_fill,
+//CupertinoIcons.building.columns_fill,
+//CupertinoIcons.mic.circle_fill,
+//CupertinoIcons.comb_fill,
+//CupertinoIcons.person.3_fill,
+ CupertinoIcons.bell_fill,
+ CupertinoIcons.hammer_fill,
+ CupertinoIcons.star_fill,
+//CupertinoIcons.crown_fill,
+ CupertinoIcons.briefcase_fill,
+//CupertinoIcons.speaker.wave.3_fill,
+//CupertinoIcons.tshirt_fill,
+ CupertinoIcons.tag_fill,
+ CupertinoIcons.airplane,
+//CupertinoIcons.pawprint_fill,
+//CupertinoIcons.case_fill,
+ CupertinoIcons.creditcard_fill,
+//CupertinoIcons.infinity.circle_fill,
+//CupertinoIcons.dice_fill,
+ CupertinoIcons.heart_fill,
+ CupertinoIcons.camera_fill,
+//CupertinoIcons.bicycle,
+//CupertinoIcons.radio_fill,
+ CupertinoIcons.car_fill,
+ CupertinoIcons.flag_fill,
+ CupertinoIcons.map_fill,
+//CupertinoIcons.figure.wave,
+//CupertinoIcons.mappin.and.ellipse,
+//CupertinoIcons.facemask_fill,
+ CupertinoIcons.eyeglasses,
+ CupertinoIcons.tram_fill,
+];
diff --git a/experimental/date_planner/lib/event_task.dart b/experimental/date_planner/lib/event_task.dart
new file mode 100644
index 000000000..d41e3f512
--- /dev/null
+++ b/experimental/date_planner/lib/event_task.dart
@@ -0,0 +1,13 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+class EventTask {
+ String text;
+ bool isCompleted;
+
+ EventTask({required this.text, this.isCompleted = false});
+
+ static List buildList(List taskDescriptions) =>
+ [for (var task in taskDescriptions) EventTask(text: task)];
+}
diff --git a/experimental/date_planner/lib/main.dart b/experimental/date_planner/lib/main.dart
new file mode 100644
index 000000000..255bb20d9
--- /dev/null
+++ b/experimental/date_planner/lib/main.dart
@@ -0,0 +1,35 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+import 'package:provider/provider.dart';
+
+import 'event_data.dart';
+import 'event_list.dart';
+
+void main() {
+ runApp(
+ ChangeNotifierProvider(
+ create: (context) => EventData(),
+ child: const DatePlannerApp(),
+ ),
+ );
+}
+
+CupertinoThemeData cupertinoLight = const CupertinoThemeData(
+ brightness: Brightness.light,
+ primaryColor: CupertinoColors.activeBlue,
+);
+
+class DatePlannerApp extends StatelessWidget {
+ const DatePlannerApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return CupertinoApp(
+ home: const EventList(),
+ theme: cupertinoLight,
+ );
+ }
+}
diff --git a/experimental/date_planner/lib/symbol_editor.dart b/experimental/date_planner/lib/symbol_editor.dart
new file mode 100644
index 000000000..fd19432be
--- /dev/null
+++ b/experimental/date_planner/lib/symbol_editor.dart
@@ -0,0 +1,108 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+
+import 'color_options.dart';
+import 'event_symbol.dart';
+
+class SymbolEditor extends StatefulWidget {
+ final IconData icon;
+ final ColorOptions color;
+
+ const SymbolEditor(this.icon, this.color, {super.key});
+
+ @override
+ State createState() => _SymbolEditorState();
+}
+
+class _SymbolEditorState extends State {
+ late IconData _currentIcon = widget.icon;
+ late ColorOptions _currentColor = widget.color;
+ _SymbolEditorState();
+
+ @override
+ Widget build(BuildContext context) {
+ // TODO(mit-mit): Should use a Sheet
+ // https://github.com/flutter/flutter/issues/42560
+ return CupertinoPageScaffold(
+ backgroundColor: CupertinoColors.white,
+ child: SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ children: [
+ Row(
+ children: [
+ const Spacer(),
+ CupertinoButton(
+ padding: EdgeInsets.zero,
+ child: const Text('Done'),
+ onPressed: () =>
+ Navigator.pop(context, (_currentIcon, _currentColor)),
+ ),
+ ],
+ ),
+ const SizedBox(height: 16),
+ Icon(
+ _currentIcon,
+ size: 48,
+ color: _currentColor.color,
+ ),
+ const SizedBox(height: 32),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ for (ColorOptions color in ColorOptions.values)
+ // TODO(mit-mit): Circles should be bigger and have less padding between them.
+ CupertinoButton(
+ padding: EdgeInsets.zero,
+ minSize: 0,
+ child: Icon(
+ CupertinoIcons.circle_fill,
+ color: color.color,
+ ),
+ onPressed: () {
+ setState(() {
+ _currentColor = color;
+ });
+ },
+ ),
+ ],
+ ),
+ const SizedBox(height: 16),
+ // TODO(mit-mit): File issue for missing Cupertino Divider widget.
+ // Should have something similar to the Material devider.
+ // https://api.flutter.dev/flutter/material/Divider-class.html
+ const Text('. . . . . . . . . . . . . . . '),
+ const SizedBox(height: 16),
+ Expanded(
+ child: GridView.count(
+ primary: false,
+ crossAxisCount: 6,
+ mainAxisSpacing: 10,
+ children: [
+ for (var icon in eventSymbols)
+ CupertinoButton(
+ padding: EdgeInsets.zero,
+ child: Icon(
+ icon,
+ size: 32,
+ ),
+ onPressed: () {
+ setState(() {
+ _currentIcon = icon;
+ });
+ },
+ )
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/experimental/date_planner/lib/task_row.dart b/experimental/date_planner/lib/task_row.dart
new file mode 100644
index 000000000..4c817ba07
--- /dev/null
+++ b/experimental/date_planner/lib/task_row.dart
@@ -0,0 +1,59 @@
+// Copyright 2024 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/cupertino.dart';
+
+import 'event_task.dart';
+
+class TaskRow extends StatefulWidget {
+ final EventTask task;
+ final bool isEditing;
+ const TaskRow({super.key, required this.task, required this.isEditing});
+
+ @override
+ State createState() => _TaskRowState();
+}
+
+class _TaskRowState extends State {
+ final _taskText = TextEditingController();
+
+ @override
+ void initState() {
+ _taskText.text = widget.task.text;
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: [
+ CupertinoButton(
+ onPressed: widget.isEditing
+ ? () {
+ setState(() {
+ widget.task.isCompleted = !widget.task.isCompleted;
+ });
+ }
+ : null,
+ child: Icon(
+ widget.task.isCompleted
+ ? CupertinoIcons.checkmark_circle_fill
+ : CupertinoIcons.circle,
+ color: CupertinoColors.black,
+ ),
+ ),
+ Expanded(
+ child: widget.isEditing
+ ? CupertinoTextField(
+ decoration: null,
+ padding: EdgeInsets.zero,
+ controller: _taskText,
+ onChanged: (value) => widget.task.text = value,
+ )
+ : Text(widget.task.text),
+ ),
+ ],
+ );
+ }
+}
diff --git a/experimental/date_planner/pubspec.yaml b/experimental/date_planner/pubspec.yaml
new file mode 100644
index 000000000..3aa873810
--- /dev/null
+++ b/experimental/date_planner/pubspec.yaml
@@ -0,0 +1,18 @@
+name: date_planner
+description: "An iOS-style date planner."
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+version: 0.1.0
+
+environment:
+ sdk: ^3.5.0
+
+dependencies:
+ flutter:
+ sdk: flutter
+ cupertino_icons: ^1.0.8
+ intl:
+ provider:
+ uuid:
+
+dev_dependencies:
+ flutter_lints: ^4.0.0