diff --git a/packages/flutter/example/.gitignore b/packages/flutter/example/.gitignore index 9457467..fd94508 100644 --- a/packages/flutter/example/.gitignore +++ b/packages/flutter/example/.gitignore @@ -7,9 +7,8 @@ pubspec.lock .metadata -# Generated platform directories — run `flutter create .` to regenerate locally +# Generated platform directories. iOS is committed for simulator demos. android/ -ios/ linux/ macos/ web/ diff --git a/packages/flutter/example/assets/mvp/ziggle-impact-ai-hackathon.png b/packages/flutter/example/assets/mvp/ziggle-impact-ai-hackathon.png new file mode 100644 index 0000000..83fd527 Binary files /dev/null and b/packages/flutter/example/assets/mvp/ziggle-impact-ai-hackathon.png differ diff --git a/packages/flutter/example/assets/mvp/ziggle-infoteam-recruit.png b/packages/flutter/example/assets/mvp/ziggle-infoteam-recruit.png new file mode 100644 index 0000000..ae93200 Binary files /dev/null and b/packages/flutter/example/assets/mvp/ziggle-infoteam-recruit.png differ diff --git a/packages/flutter/example/ios/.gitignore b/packages/flutter/example/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/packages/flutter/example/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/packages/flutter/example/ios/Flutter/AppFrameworkInfo.plist b/packages/flutter/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..391a902 --- /dev/null +++ b/packages/flutter/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/packages/flutter/example/ios/Flutter/Debug.xcconfig b/packages/flutter/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/packages/flutter/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/packages/flutter/example/ios/Flutter/Release.xcconfig b/packages/flutter/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/packages/flutter/example/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/packages/flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/flutter/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..627eed1 --- /dev/null +++ b/packages/flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,644 @@ +// !$*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 */; }; + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.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 */; }; +/* 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 = ""; }; + 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; 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 = ""; }; + 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 = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, + 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 */, + 7884E8672EC3CC0400C636F2 /* SceneDelegate.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; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); + 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; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + ); + 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 */, + 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift 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 = 13.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)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.idsFlutterExample; + 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.idsFlutterExample.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.idsFlutterExample.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.idsFlutterExample.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 = 13.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 = 13.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)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.idsFlutterExample; + 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)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.idsFlutterExample; + 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 */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/packages/flutter/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..c3fedb2 --- /dev/null +++ b/packages/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/flutter/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/flutter/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/packages/flutter/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/packages/flutter/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/packages/flutter/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/flutter/example/ios/Runner/AppDelegate.swift b/packages/flutter/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..c30b367 --- /dev/null +++ b/packages/flutter/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,16 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } +} diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/packages/flutter/example/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/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..7353c41 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..6ed2d93 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cd7b00 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..fe73094 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..321773c Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..502f463 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..e9f5fea Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..84ac32a Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..8953cba Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..0467bf1 Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/packages/flutter/example/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/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/packages/flutter/example/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/packages/flutter/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/flutter/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/packages/flutter/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/flutter/example/ios/Runner/Base.lproj/Main.storyboard b/packages/flutter/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/packages/flutter/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/flutter/example/ios/Runner/Info.plist b/packages/flutter/example/ios/Runner/Info.plist new file mode 100644 index 0000000..c171a97 --- /dev/null +++ b/packages/flutter/example/ios/Runner/Info.plist @@ -0,0 +1,70 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Ids Flutter Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ids_flutter_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/packages/flutter/example/ios/Runner/Runner-Bridging-Header.h b/packages/flutter/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/packages/flutter/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/flutter/example/ios/Runner/SceneDelegate.swift b/packages/flutter/example/ios/Runner/SceneDelegate.swift new file mode 100644 index 0000000..b9ce8ea --- /dev/null +++ b/packages/flutter/example/ios/Runner/SceneDelegate.swift @@ -0,0 +1,6 @@ +import Flutter +import UIKit + +class SceneDelegate: FlutterSceneDelegate { + +} diff --git a/packages/flutter/example/ios/RunnerTests/RunnerTests.swift b/packages/flutter/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/packages/flutter/example/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/packages/flutter/example/lib/components/mvp_frames_usecase.dart b/packages/flutter/example/lib/components/mvp_frames_usecase.dart new file mode 100644 index 0000000..a3868f9 --- /dev/null +++ b/packages/flutter/example/lib/components/mvp_frames_usecase.dart @@ -0,0 +1,1826 @@ +import 'package:flutter/material.dart'; +import 'package:hugeicons/hugeicons.dart'; +import 'package:ids_flutter/ids.dart'; +import 'package:ids_flutter/tokens/ids_typography.dart'; +import 'package:widgetbook/widgetbook.dart'; + +const _recruitPosterAsset = 'assets/mvp/ziggle-infoteam-recruit.png'; +const _hackathonPosterAsset = 'assets/mvp/ziggle-impact-ai-hackathon.png'; + +final mvpFrameUseCases = [ + WidgetbookUseCase( + name: 'Ziggle Notice List', + builder: (context) => _withTheme( + context, + initialColor: IdsColor.orange, + child: const _Phone(child: _ZiggleNoticeListFrame()), + ), + ), + WidgetbookUseCase( + name: 'Ziggle Groups', + builder: (context) => _withTheme( + context, + initialColor: IdsColor.orange, + child: const _Phone(child: _ZiggleGroupsFrame()), + ), + ), + WidgetbookUseCase( + name: 'Ziggle Notice Detail', + builder: (context) => _withTheme( + context, + initialColor: IdsColor.orange, + child: const _Phone(child: _ZiggleNoticeDetailFrame()), + ), + ), + WidgetbookUseCase( + name: 'Ziggle Profile', + builder: (context) => _withTheme( + context, + initialColor: IdsColor.orange, + child: const _Phone(child: _ZiggleProfileFrame()), + ), + ), + WidgetbookUseCase( + name: 'Potg Main List', + builder: (context) => _withTheme( + context, + initialColor: IdsColor.green, + child: const _Phone(child: _PotgMainListFrame()), + ), + ), + WidgetbookUseCase( + name: 'Potg Create Time', + builder: (context) => _withTheme( + context, + initialColor: IdsColor.green, + child: Center(child: _Phone(child: _PotgCreateTimeFrame())), + ), + ), + WidgetbookUseCase( + name: 'Potg Search Empty', + builder: (context) => _withTheme( + context, + initialColor: IdsColor.green, + child: const _Phone(child: _PotgSearchEmptyFrame()), + ), + ), + WidgetbookUseCase( + name: 'Potg Filter Dialog', + builder: (context) => _withTheme( + context, + initialColor: IdsColor.green, + child: const _Phone(child: _PotgFilterDialogFrame()), + ), + ), +]; + +const mvpFrameIndex = int.fromEnvironment('MVP_FRAME_INDEX'); + +class MvpFramesApp extends StatelessWidget { + const MvpFramesApp({super.key}); + + static const _frames = [ + _MvpFrameSpec( + label: '공지 목록', + color: IdsColor.orange, + child: _ZiggleNoticeListFrame(), + ), + _MvpFrameSpec( + label: '공지 상세', + color: IdsColor.orange, + child: _ZiggleNoticeDetailFrame(), + ), + _MvpFrameSpec( + label: '프로필', + color: IdsColor.orange, + child: _ZiggleProfileFrame(), + ), + _MvpFrameSpec( + label: '그룹', + color: IdsColor.orange, + child: _ZiggleGroupsFrame(), + ), + _MvpFrameSpec( + label: '팟 리스트', + color: IdsColor.green, + child: _PotgMainListFrame(), + ), + _MvpFrameSpec( + label: '팟 생성', + color: IdsColor.green, + surfaceBackground: true, + child: _PotgCreateTimeFrame(), + ), + _MvpFrameSpec( + label: '팟 검색', + color: IdsColor.green, + child: _PotgSearchEmptyFrame(), + ), + _MvpFrameSpec( + label: '팟 필터', + color: IdsColor.green, + child: _PotgFilterDialogFrame(), + ), + ]; + + @override + Widget build(BuildContext context) { + final index = mvpFrameIndex.clamp(0, _frames.length - 1); + final frame = _frames[index]; + + return ThemeProvider( + color: frame.color, + mode: IdsMode.light, + child: Builder( + builder: (context) { + final theme = ThemeProvider.of(context); + final background = frame.surfaceBackground + ? theme.surface + : theme.muted; + + return MaterialApp( + debugShowCheckedModeBanner: false, + theme: ThemeData( + fontFamily: IdsTypography.sansFontFamily, + package: IdsTypography.sansFontPackage, + scaffoldBackgroundColor: background, + ), + home: Scaffold( + backgroundColor: background, + body: SafeArea(bottom: false, child: frame.child), + ), + ); + }, + ), + ); + } +} + +class _MvpFrameSpec { + const _MvpFrameSpec({ + required this.label, + required this.color, + required this.child, + this.surfaceBackground = false, + }); + + final String label; + final IdsColor color; + final Widget child; + final bool surfaceBackground; +} + +Widget _withTheme( + BuildContext context, { + required IdsColor initialColor, + required Widget child, +}) { + final color = context.knobs.object.dropdown( + label: 'Color', + options: IdsColor.values, + initialOption: initialColor, + labelBuilder: (c) => c.name, + ); + final mode = context.knobs.object.dropdown( + label: 'Mode', + options: IdsMode.values, + initialOption: IdsMode.light, + labelBuilder: (m) => m.name, + ); + + return ThemeProvider( + color: color, + mode: mode, + child: Builder( + builder: (context) { + final theme = ThemeProvider.of(context); + + return Scaffold( + backgroundColor: theme.muted, + body: Center(child: child), + ); + }, + ), + ); +} + +class _Phone extends StatelessWidget { + const _Phone({required this.child}); + + final Widget child; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return ClipRect( + child: Container( + width: 390, + height: 760, + color: theme.muted, + child: child, + ), + ); + } +} + +class _ZiggleNoticeListFrame extends StatelessWidget { + const _ZiggleNoticeListFrame(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Stack( + children: [ + Column( + children: [ + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(14, 28, 14, 96), + child: IdsVStack( + gap: 18, + crossAxis: CrossAxis.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 2), + child: IdsHStack( + gap: 8, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: [ + const Text('🔥', style: TextStyle(fontSize: 28)), + Text( + 'zgl', + style: IdsTypography.title.copyWith( + color: theme.onSurface, + fontWeight: FontWeight.w800, + height: 1, + ), + ), + ], + ), + ), + const _ZiggleCategoryRail(), + const _ZiggleNoticeFeedCard( + author: '홍길동', + title: '공지 제목', + dueLabel: '12일 남음', + posterAsset: _recruitPosterAsset, + tags: ['# 태그1', '# 태그1', '# 태그1', '# 태그1', '# 태그1'], + ), + const _ZiggleNoticeFeedCard( + author: 'GDSC GIST', + title: 'Impact AI Hackathon 참가자 모집', + posterAsset: _hackathonPosterAsset, + tags: ['#해커톤', '#AI', '#행사', '#GDSC'], + ), + ], + ), + ), + ), + _ZiggleBottomNavigation(currentIndex: 0), + ], + ), + ], + ); + } +} + +class _ZiggleCategoryRail extends StatelessWidget { + const _ZiggleCategoryRail(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return SizedBox( + height: 48, + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + _ZiggleCategoryPill( + label: '일반', + icon: HugeIcons.strokeRoundedMegaphone01, + selected: true, + ), + _ZiggleCategoryPill(icon: HugeIcons.strokeRoundedCalendar03), + _ZiggleCategoryPill(icon: HugeIcons.strokeRoundedGift), + _ZiggleCategoryPill(icon: HugeIcons.strokeRoundedTarget02), + Container( + width: 78, + margin: const EdgeInsets.only(left: 10), + decoration: BoxDecoration( + color: theme.secondary, + borderRadius: BorderRadius.circular(18), + ), + ), + ], + ), + ); + } +} + +class _ZiggleCategoryPill extends StatelessWidget { + const _ZiggleCategoryPill({ + required this.icon, + this.label, + this.selected = false, + }); + + final List> icon; + final String? label; + final bool selected; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Container( + height: 48, + margin: const EdgeInsets.only(right: 10), + padding: EdgeInsets.symmetric(horizontal: label == null ? 20 : 22), + decoration: BoxDecoration( + color: selected ? theme.primary : theme.secondary, + borderRadius: BorderRadius.circular(18), + ), + child: IdsHStack( + gap: 8, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: [ + IconTheme( + data: IconThemeData( + color: selected ? theme.onPrimary : theme.onSecondary, + size: 22, + ), + child: _HugeIcon(icon), + ), + if (label != null) + Text( + label!, + style: IdsTypography.body.copyWith( + color: selected ? theme.onPrimary : theme.onSecondary, + fontWeight: FontWeight.w800, + leadingDistribution: TextLeadingDistribution.even, + ), + ), + ], + ), + ); + } +} + +class _ZiggleNoticeFeedCard extends StatelessWidget { + const _ZiggleNoticeFeedCard({ + required this.author, + required this.title, + required this.posterAsset, + required this.tags, + this.dueLabel, + }); + + final String author; + final String title; + final String posterAsset; + final List tags; + final String? dueLabel; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return IdsCard( + variant: IdsCardVariant.elevated, + child: Padding( + padding: const EdgeInsets.fromLTRB(14, 14, 14, 16), + child: IdsVStack( + gap: 12, + crossAxis: CrossAxis.start, + children: [ + Row( + children: [ + const IdsAvatar(name: '홍길동', size: IdsSize.lg), + const SizedBox(width: 10), + Expanded( + child: IdsVStack( + gap: 2, + crossAxis: CrossAxis.start, + fit: IdsStackFit.content, + children: [ + IdsHStack( + gap: 4, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: [ + IdsText(author, variant: IdsTextVariant.body), + IconTheme( + data: IconThemeData(color: theme.primary, size: 18), + child: const _HugeIcon( + HugeIcons.strokeRoundedCheckmarkBadge01, + ), + ), + ], + ), + IdsText( + '10분 전', + variant: IdsTextVariant.caption, + color: theme.onMuted, + ), + ], + ), + ), + if (dueLabel != null) + Container( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + decoration: BoxDecoration( + color: theme.primary, + borderRadius: BorderRadius.circular(8), + ), + child: IdsText( + dueLabel!, + variant: IdsTextVariant.caption, + color: theme.onPrimary, + ), + ), + ], + ), + IdsHStack( + gap: 8, + crossAxis: CrossAxis.center, + children: [ + Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: theme.primary, + shape: BoxShape.circle, + ), + ), + Expanded(child: IdsText(title, variant: IdsTextVariant.body)), + ], + ), + Center( + child: _NoticePoster( + assetPath: posterAsset, + height: 230, + width: 250, + ), + ), + Wrap( + spacing: 8, + runSpacing: 8, + children: [for (final tag in tags) IdsBadge(tag)], + ), + Row( + children: [ + IconTheme( + data: IconThemeData(color: theme.primary, size: 28), + child: const _HugeIcon(HugeIcons.strokeRoundedFire), + ), + const SizedBox(width: 6), + const IdsText('10', variant: IdsTextVariant.body), + const SizedBox(width: 18), + IconTheme( + data: IconThemeData(color: theme.primary, size: 28), + child: const _HugeIcon(HugeIcons.strokeRoundedBookmark01), + ), + const Spacer(), + IconTheme( + data: IconThemeData(color: theme.onSurface, size: 24), + child: const _HugeIcon(HugeIcons.strokeRoundedShare01), + ), + ], + ), + ], + ), + ), + ); + } +} + +class _ZiggleGroupsFrame extends StatelessWidget { + const _ZiggleGroupsFrame(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Column( + children: [ + const _GroupHeader(), + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final panelHeight = constraints.maxHeight - 49; + + return IdsTabs( + defaultValue: 'notice', + items: [ + IdsTabItem( + value: 'intro', + label: '소개', + child: SizedBox( + height: panelHeight, + child: const Padding( + padding: EdgeInsets.all(24), + child: IdsText( + '지속 가능한 개발 문화를 통해 지스트 학부생의 삶의 질을 높이는 팀입니다.', + variant: IdsTextVariant.label, + ), + ), + ), + ), + IdsTabItem( + value: 'notice', + label: '공지', + child: SizedBox( + height: panelHeight, + child: SingleChildScrollView( + padding: const EdgeInsets.all(20), + child: IdsVStack( + gap: 16, + children: [ + const _GroupNoticeCard(), + IdsCard( + variant: IdsCardVariant.elevated, + child: IdsCardContent( + child: IdsVStack( + gap: 12, + crossAxis: CrossAxis.start, + children: [ + const IdsText( + '2026 봄학기 개발자 모집 안내', + variant: IdsTextVariant.body, + ), + const _NoticePoster(), + Wrap( + spacing: 8, + children: const [ + IdsBadge('#공지'), + IdsBadge('#행사'), + IdsBadge('#지원'), + ], + ), + IdsText( + '10일 남음', + variant: IdsTextVariant.caption, + color: theme.primary, + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + IdsTabItem( + value: 'members', + label: '멤버', + child: SizedBox( + height: panelHeight, + child: const Padding( + padding: EdgeInsets.all(24), + child: IdsText('멤버 목록', variant: IdsTextVariant.label), + ), + ), + ), + ], + ); + }, + ), + ), + ], + ); + } +} + +class _GroupHeader extends StatelessWidget { + const _GroupHeader(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return ColoredBox( + color: theme.surface, + child: Padding( + padding: const EdgeInsets.all(24), + child: IdsVStack( + gap: 18, + children: [ + const IdsHStack( + gap: 16, + crossAxis: CrossAxis.center, + children: [ + IdsAvatar(name: '인포팀', size: IdsSize.xxl), + Expanded( + child: IdsVStack( + gap: 4, + crossAxis: CrossAxis.start, + children: [ + IdsText('GIST 인포팀', variant: IdsTextVariant.title), + IdsText( + '구독자 248명 · 게시글 12개', + variant: IdsTextVariant.caption, + ), + ], + ), + ), + ], + ), + IdsCard( + variant: IdsCardVariant.filled, + child: IdsCardContent( + child: IdsText( + 'GIST 학생을 위한 웹 서비스와 인증 인프라를 만들고 운영하는 개발팀입니다.', + variant: IdsTextVariant.label, + color: theme.onMuted, + ), + ), + ), + IdsButton(onPressed: () {}, children: const [Text('즐겨찾기')]), + ], + ), + ), + ); + } +} + +class _GroupNoticeCard extends StatelessWidget { + const _GroupNoticeCard(); + + @override + Widget build(BuildContext context) { + return IdsCard( + variant: IdsCardVariant.elevated, + child: IdsCardContent( + child: IdsVStack( + gap: 12, + crossAxis: CrossAxis.start, + children: [ + const IdsHStack( + gap: 10, + crossAxis: CrossAxis.center, + children: [ + IdsAvatar(name: '인포팀'), + IdsVStack( + gap: 2, + crossAxis: CrossAxis.start, + fit: IdsStackFit.content, + children: [ + IdsText('GIST 인포팀', variant: IdsTextVariant.caption), + IdsText('12분 전', variant: IdsTextVariant.caption), + ], + ), + ], + ), + const IdsText('2026 봄학기 인포팀 개발자 모집', variant: IdsTextVariant.body), + const _NoticePoster(), + Wrap( + spacing: 8, + children: const [ + IdsBadge('#모집'), + IdsBadge('#개발'), + IdsBadge('#인포팀'), + ], + ), + ], + ), + ), + ); + } +} + +class _PhoneHeader extends StatelessWidget { + const _PhoneHeader({required this.title, this.backLabel}); + + final String title; + final String? backLabel; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Container( + width: double.infinity, + height: 56, + decoration: BoxDecoration( + color: theme.surface, + border: Border(bottom: BorderSide(color: theme.outline)), + ), + child: Stack( + alignment: Alignment.center, + children: [ + if (backLabel != null) + Positioned( + left: 16, + top: 0, + bottom: 0, + child: Center( + child: IdsText( + backLabel!, + variant: IdsTextVariant.label, + color: theme.primary, + ), + ), + ), + IdsText(title, variant: IdsTextVariant.label), + ], + ), + ); + } +} + +class _ZiggleNoticeDetailFrame extends StatelessWidget { + const _ZiggleNoticeDetailFrame(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Column( + children: [ + const _PhoneHeader(title: '공지 상세', backLabel: '공지'), + Expanded( + child: ColoredBox( + color: theme.surface, + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: IdsVStack( + gap: 20, + crossAxis: CrossAxis.start, + children: [ + IdsButton( + onPressed: () {}, + children: const [Text('마감기한 2026.03.30. 18:00')], + ), + const IdsHStack( + gap: 10, + crossAxis: CrossAxis.center, + children: [ + IdsAvatar(name: '인포팀'), + IdsText('인포팀 · 32분 전', variant: IdsTextVariant.label), + ], + ), + const IdsText( + '2026 봄학기 인포팀 개발자 모집', + variant: IdsTextVariant.title, + ), + Wrap( + spacing: 8, + runSpacing: 8, + children: const [ + IdsBadge('#모집'), + IdsBadge('#인포팀'), + IdsBadge('#개발'), + IdsBadge('#앱개발'), + IdsBadge('#디자인시스템'), + IdsBadge('#서비스운영'), + ], + ), + const _NoticePoster(), + const IdsText( + 'GIST 인포팀에서 2026 봄학기 신규 멤버를 모집합니다.\n지원서 작성 구글 폼 링크', + variant: IdsTextVariant.label, + ), + const IdsText( + '인포팀은 지글(Ziggle), IdP, 디자인 시스템 등 학생들이 매일 사용하는 서비스를 설계하고 운영합니다. 제품 개발과 서비스 운영을 함께 경험하고 싶은 분을 기다립니다.', + variant: IdsTextVariant.label, + ), + const _ReactionBar(), + ], + ), + ), + ), + ), + ], + ); + } +} + +class _NoticePoster extends StatelessWidget { + const _NoticePoster({ + this.assetPath = _recruitPosterAsset, + this.height = 320, + this.width, + }); + + final String assetPath; + final double height; + final double? width; + + @override + Widget build(BuildContext context) { + return Container( + height: height, + width: width ?? double.infinity, + alignment: Alignment.center, + decoration: BoxDecoration( + color: ThemeProvider.of(context).surface, + borderRadius: BorderRadius.circular(24), + border: Border.all(color: ThemeProvider.of(context).outline), + ), + clipBehavior: Clip.antiAlias, + child: Image.asset( + assetPath, + fit: BoxFit.contain, + width: double.infinity, + height: double.infinity, + ), + ); + } +} + +class _ReactionBar extends StatelessWidget { + const _ReactionBar(); + + @override + Widget build(BuildContext context) { + return const Wrap( + spacing: 8, + runSpacing: 8, + children: [ + _ReactionChip( + label: '268', + icon: HugeIcons.strokeRoundedFire, + selected: true, + width: 70, + ), + _ReactionChip( + label: '37', + icon: HugeIcons.strokeRoundedSurprise, + width: 64, + ), + _ReactionChip( + label: '2', + icon: HugeIcons.strokeRoundedCrying, + width: 58, + ), + _ReactionChip( + label: '1', + icon: HugeIcons.strokeRoundedIdea01, + width: 58, + ), + _ReactionChip( + label: '0', + icon: HugeIcons.strokeRoundedSad01, + width: 58, + ), + _ReactionChip( + label: '공유하기', + icon: HugeIcons.strokeRoundedShare01, + width: 112, + ), + _ReactionChip( + label: '링크 복사하기', + icon: HugeIcons.strokeRoundedCopyLink, + width: 136, + ), + ], + ); + } +} + +class _ReactionChip extends StatelessWidget { + const _ReactionChip({ + required this.label, + required this.width, + this.icon, + this.selected = false, + }); + + final String label; + final double width; + final List>? icon; + final bool selected; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return SizedBox( + width: width, + child: Container( + height: 36, + alignment: Alignment.center, + decoration: BoxDecoration( + color: selected ? theme.primary : theme.secondary, + borderRadius: BorderRadius.circular(16), + ), + child: IconTheme( + data: IconThemeData( + color: selected ? theme.onPrimary : theme.onSecondary, + size: 17, + ), + child: IdsHStack( + gap: icon == null ? 0 : 5, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: [ + if (icon != null) _HugeIcon(icon!), + Text( + label, + style: IdsTypography.caption.copyWith( + color: selected ? theme.onPrimary : theme.onSecondary, + fontWeight: FontWeight.w700, + leadingDistribution: TextLeadingDistribution.even, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ), + ); + } +} + +class _ZiggleProfileFrame extends StatelessWidget { + const _ZiggleProfileFrame(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Column( + children: [ + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(24, 28, 24, 32), + child: IdsVStack( + gap: 24, + children: [ + IdsCard( + size: IdsCardSize.lg, + child: Padding( + padding: const EdgeInsets.all(28), + child: IdsVStack( + gap: 10, + crossAxis: CrossAxis.center, + children: [ + const IdsAvatar(name: '류현승', size: IdsSize.xxl), + const IdsVStack( + gap: 4, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: [ + IdsText('류현승', variant: IdsTextVariant.title), + IdsText('20255070', variant: IdsTextVariant.body), + ], + ), + IdsText( + 'rhseungg@gm.gist.ac.kr', + variant: IdsTextVariant.caption, + color: theme.onMuted, + ), + ], + ), + ), + ), + _ProfileSection( + items: const [ + ( + HugeIcons.strokeRoundedUserCircle02, + '계정', + '회원 정보 수정 · 아이디 및 비밀번호 변경', + ), + (HugeIcons.strokeRoundedUserRemove01, '회원 탈퇴', null), + (HugeIcons.strokeRoundedLogout03, '로그아웃', null), + ], + ), + _ProfileSection( + items: const [ + (HugeIcons.strokeRoundedSettings02, '설정', '알림 · 언어 · 정보'), + ( + HugeIcons.strokeRoundedMessageEdit01, + '피드백 · 버그 제보하기', + null, + ), + ], + ), + ], + ), + ), + ), + IdsBottomNavigation( + currentIndex: 2, + onTap: (_) {}, + items: [ + _navItem(HugeIcons.strokeRoundedHome01, '홈'), + _navItem(HugeIcons.strokeRoundedBookmark01, '즐겨찾기'), + _navItem(HugeIcons.strokeRoundedUserCircle02, '프로필'), + ], + ), + ], + ); + } +} + +class _ProfileSection extends StatelessWidget { + const _ProfileSection({required this.items}); + + final List<(List>, String, String?)> items; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return IdsCard( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8), + child: Column( + children: [ + for (var i = 0; i < items.length; i++) ...[ + IdsItem( + onPressed: () {}, + children: [ + IdsItemLeading( + child: IconTheme( + data: IconThemeData(color: theme.onSurface, size: 22), + child: _HugeIcon(items[i].$1), + ), + ), + IdsItemContent( + children: [ + IdsItemTitle(items[i].$2), + if (items[i].$3 != null) IdsItemDescription(items[i].$3!), + ], + ), + ], + ), + if (i < items.length - 1) const IdsDivider(), + ], + ], + ), + ), + ); + } +} + +class _PotgMainListFrame extends StatelessWidget { + const _PotgMainListFrame(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Stack( + children: [ + Column( + children: [ + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(24, 24, 24, 128), + child: IdsVStack( + gap: 20, + crossAxis: CrossAxis.start, + children: [ + const IdsText('팟쥐', variant: IdsTextVariant.title), + const _WeekStatusCard(), + IdsText( + '2025/11/15 토요일', + variant: IdsTextVariant.caption, + color: theme.onMuted, + ), + const _TaxiPotCard( + from: '지스트', + to: '광주송정역', + time: '13:10~14:00', + capacity: '1/4', + ), + const _TaxiPotCard( + from: '지스트', + to: '유스퀘어', + time: '17:30~18:10', + capacity: '2/4', + ), + const _TaxiPotCard( + from: '광주송정역', + to: '지스트', + time: '21:20~22:00', + capacity: '3/4', + ), + const _TaxiPotCard( + from: '지스트', + to: '광주공항', + time: '08:40~09:20', + capacity: '1/3', + ), + ], + ), + ), + ), + IdsBottomNavigation( + currentIndex: 0, + onTap: (_) {}, + items: [ + _navItem(HugeIcons.strokeRoundedHome01, '모든 팟'), + _navItem(HugeIcons.strokeRoundedSearch01, '팟 검색'), + _navItem(HugeIcons.strokeRoundedMessage01, '채팅방'), + _navItem(HugeIcons.strokeRoundedUserCircle02, '내 정보'), + ], + ), + ], + ), + const _PotgFloatingButton(), + ], + ); + } +} + +class _WeekStatusCard extends StatelessWidget { + const _WeekStatusCard(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + const days = ['일', '월', '화', '수', '목', '금', '토']; + + return IdsCard( + child: IdsCardContent( + child: IdsVStack( + gap: 16, + crossAxis: CrossAxis.start, + children: [ + const IdsText('요일 별 팟 현황', variant: IdsTextVariant.body), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + for (var i = 0; i < days.length; i++) + Column( + children: [ + IdsText(days[i], variant: IdsTextVariant.caption), + const SizedBox(height: 8), + for (var row = 0; row < 3; row++) ...[ + Container( + width: 34, + height: 34, + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: i == 6 && row == 1 ? theme.primary : null, + border: Border.all(color: theme.outline), + ), + child: IdsText( + i == 6 && row == 1 ? '5' : (row == 0 ? '0' : '1'), + variant: IdsTextVariant.caption, + color: i == 6 && row == 1 + ? theme.onPrimary + : theme.onSurface, + ), + ), + if (row < 2) const SizedBox(height: 8), + ], + ], + ), + ], + ), + ], + ), + ), + ); + } +} + +class _TaxiPotCard extends StatelessWidget { + const _TaxiPotCard({ + this.from = '지스트', + this.to = '광주송정역', + this.time = '13:10~14:00', + this.capacity = '1/4', + }); + + final String from; + final String to; + final String time; + final String capacity; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: theme.surface, + borderRadius: BorderRadius.circular(18), + ), + foregroundDecoration: BoxDecoration( + borderRadius: BorderRadius.circular(18), + border: Border.all(color: theme.outline), + ), + child: Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(18, 16, 14, 16), + child: IdsVStack( + gap: 10, + crossAxis: CrossAxis.start, + children: [ + IdsHStack( + gap: 8, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: [ + IconTheme( + data: IconThemeData(color: theme.primary, size: 20), + child: const _HugeIcon(HugeIcons.strokeRoundedRoute01), + ), + Expanded( + child: Text( + '$from → $to', + style: IdsTypography.body.copyWith( + color: theme.onSurface, + fontWeight: FontWeight.w600, + leadingDistribution: TextLeadingDistribution.even, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + IdsText(time, variant: IdsTextVariant.body), + ], + ), + ), + ), + Container( + width: 86, + height: 96, + alignment: Alignment.center, + decoration: BoxDecoration( + color: theme.secondary, + border: Border(left: BorderSide(color: theme.outline)), + ), + child: IdsVStack( + gap: 4, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: [ + const IdsText('정원', variant: IdsTextVariant.label), + IdsText( + capacity, + variant: IdsTextVariant.title, + color: theme.primary, + ), + ], + ), + ), + ], + ), + ); + } +} + +class _PotgSearchEmptyFrame extends StatelessWidget { + const _PotgSearchEmptyFrame(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Stack( + children: [ + Column( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(24), + child: IdsVStack( + gap: 24, + crossAxis: CrossAxis.start, + children: [ + const IdsText('팟 검색', variant: IdsTextVariant.title), + Expanded( + child: Center( + child: IdsEmpty( + children: [ + IdsEmptyMedia( + child: Container( + width: 84, + height: 84, + alignment: Alignment.center, + decoration: BoxDecoration( + color: theme.secondary, + shape: BoxShape.circle, + ), + child: IconTheme( + data: IconThemeData( + color: theme.primary, + size: 48, + ), + child: const _HugeIcon( + HugeIcons.strokeRoundedSad01, + ), + ), + ), + ), + IdsText( + '해당 조건의 택시 팟이 존재하지 않습니다', + variant: IdsTextVariant.label, + color: theme.primary, + align: TextAlign.center, + ), + IdsEmptyActions( + children: [ + IdsButton( + onPressed: () {}, + variant: IdsVariant.outline, + children: const [ + _HugeIcon(HugeIcons.strokeRoundedCar03), + Text('새 팟 만들기'), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ), + ), + ), + _PotgBottomNavigation(currentIndex: 1), + ], + ), + const _PotgFloatingButton(), + ], + ); + } +} + +class _PotgFilterDialogFrame extends StatefulWidget { + const _PotgFilterDialogFrame(); + + @override + State<_PotgFilterDialogFrame> createState() => _PotgFilterDialogFrameState(); +} + +class _PotgFilterDialogFrameState extends State<_PotgFilterDialogFrame> { + var checked = true; + var open = true; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Stack( + children: [ + Column( + children: [ + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: IdsVStack( + gap: 20, + crossAxis: CrossAxis.start, + children: [ + const IdsText('팟 검색', variant: IdsTextVariant.title), + const IdsText('노선 필터', variant: IdsTextVariant.caption), + const IdsCard( + child: IdsCardContent( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IdsText('지스트', variant: IdsTextVariant.body), + IdsText('→', variant: IdsTextVariant.body), + IdsText('유스퀘어', variant: IdsTextVariant.body), + ], + ), + ), + ), + const IdsText('날짜 필터', variant: IdsTextVariant.caption), + const _CalendarFilterCard(), + IdsHStack( + gap: 8, + crossAxis: CrossAxis.center, + children: [ + IdsCheckbox( + checked: checked, + semanticLabel: '정원이 가득 찬 팟 숨기기', + onChanged: (value) => setState(() => checked = value), + ), + const Expanded( + child: IdsText( + '정원이 가득 찬 팟 숨기기', + variant: IdsTextVariant.caption, + ), + ), + ], + ), + IdsButton( + onPressed: () => setState(() => open = true), + children: const [Text('적용')], + ), + _TaxiPotCard(), + ], + ), + ), + ), + _PotgBottomNavigation(currentIndex: 1), + ], + ), + const _PotgFloatingButton(), + IdsDialog( + open: open, + onOpenChanged: (value) => setState(() => open = value), + children: [ + const IdsDialogHeader(children: [IdsDialogTitle('입장하시겠습니까?')]), + const IdsDialogContent( + child: IdsVStack( + gap: 8, + crossAxis: CrossAxis.start, + children: [ + IdsText('노선 광주송정역 → 지스트', variant: IdsTextVariant.label), + IdsText( + '날짜 2025년 12월 13일 토요일', + variant: IdsTextVariant.label, + ), + IdsText('시간 23:30~01:00', variant: IdsTextVariant.label), + IdsText( + '참여자 목록 김민준, 박서연, 이서연', + variant: IdsTextVariant.label, + ), + ], + ), + ), + IdsDialogFooter( + children: [ + IdsButton( + onPressed: () => setState(() => open = false), + variant: IdsVariant.ghost, + children: const [Text('아니요')], + ), + IdsButton( + onPressed: () => setState(() => open = false), + variant: IdsVariant.ghost, + children: [Text('네', style: TextStyle(color: theme.primary))], + ), + ], + ), + ], + ), + ], + ); + } +} + +class _CalendarFilterCard extends StatelessWidget { + const _CalendarFilterCard(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return IdsCard( + child: IdsCardContent( + child: IdsVStack( + gap: 16, + children: [ + const IdsText( + '2025년 11월', + variant: IdsTextVariant.body, + align: TextAlign.center, + ), + Wrap( + spacing: 18, + runSpacing: 14, + children: [ + for (var day = 8; day <= 22; day++) + Container( + width: 34, + height: 34, + alignment: Alignment.center, + decoration: BoxDecoration( + color: day == 14 ? theme.primary : null, + borderRadius: BorderRadius.circular(12), + ), + child: IdsText( + '$day', + variant: IdsTextVariant.caption, + color: day == 14 ? theme.onPrimary : theme.onSurface, + ), + ), + ], + ), + ], + ), + ), + ); + } +} + +class _PotgCreateTimeFrame extends StatelessWidget { + const _PotgCreateTimeFrame(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return ColoredBox( + color: theme.surface, + child: SizedBox.expand( + child: SingleChildScrollView( + padding: const EdgeInsets.fromLTRB(24, 28, 24, 40), + child: IdsVStack( + gap: 20, + crossAxis: CrossAxis.start, + children: [ + const IdsText('팟 생성', variant: IdsTextVariant.title), + _StepRow( + index: '1', + label: '지스트 → 광주송정역', + filled: true, + editable: true, + ), + _StepRow( + index: '2', + label: '11월 14일 금요일', + filled: true, + editable: true, + ), + _StepRow(index: '3', label: '시간대 설정', filled: false), + const IdsCard( + child: IdsCardContent( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _TimeSummary(label: '금요일 오전', time: '9:41'), + IdsText('~', variant: IdsTextVariant.title), + _TimeSummary(label: '금요일 오후', time: '12:30'), + ], + ), + ), + ), + const IdsText( + '출발 가능한 가장 늦은 시각을 설정하세요', + variant: IdsTextVariant.body, + ), + const _TimeWheelPickerMock(), + ], + ), + ), + ), + ); + } +} + +class _StepRow extends StatelessWidget { + const _StepRow({ + required this.index, + required this.label, + required this.filled, + this.editable = false, + }); + + final String index; + final String label; + final bool filled; + final bool editable; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return IdsHStack( + gap: 12, + crossAxis: CrossAxis.center, + children: [ + Container( + width: 34, + height: 34, + alignment: Alignment.center, + decoration: BoxDecoration( + color: filled ? theme.primary : null, + borderRadius: BorderRadius.circular(10), + border: filled ? null : Border.all(color: theme.primary, width: 2), + ), + child: IdsText( + index, + variant: IdsTextVariant.body, + color: filled ? theme.onPrimary : theme.primary, + ), + ), + Expanded(child: IdsText(label, variant: IdsTextVariant.body)), + if (editable) + IconTheme( + data: IconThemeData(color: theme.onMuted, size: 20), + child: const _HugeIcon(HugeIcons.strokeRoundedEdit02), + ), + ], + ); + } +} + +class _TimeWheelPickerMock extends StatelessWidget { + const _TimeWheelPickerMock(); + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return Container( + height: 250, + width: double.infinity, + decoration: BoxDecoration( + color: theme.muted, + borderRadius: BorderRadius.circular(12), + ), + child: Stack( + alignment: Alignment.center, + children: [ + Positioned( + top: 98, + left: 32, + right: 32, + child: Container( + height: 32, + decoration: BoxDecoration( + color: theme.surface.withValues(alpha: 0.56), + borderRadius: BorderRadius.circular(8), + ), + ), + ), + Positioned( + top: 28, + child: IdsHStack( + gap: 28, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: const [ + _WheelColumn(values: ['6', '7', '8', '9', '10', '11', '12']), + _WheelColumn( + values: ['38', '39', '40', '41', '42', '43', '44'], + ), + _WheelColumn(values: ['', '', '', 'AM', 'PM', '', '']), + ], + ), + ), + Positioned( + bottom: 24, + child: SizedBox( + width: 64, + height: 42, + child: IdsButton( + onPressed: () {}, + variant: IdsVariant.outline, + size: IdsSize.sm, + children: const [Text('확인')], + ), + ), + ), + ], + ), + ); + } +} + +class _WheelColumn extends StatelessWidget { + const _WheelColumn({required this.values}); + + final List values; + + @override + Widget build(BuildContext context) { + final theme = ThemeProvider.of(context); + + return SizedBox( + width: 50, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (var i = 0; i < values.length; i++) + SizedBox( + height: 24, + child: Center( + child: IdsText( + values[i], + variant: i == 3 + ? IdsTextVariant.body + : IdsTextVariant.caption, + color: theme.onMuted.withValues( + alpha: switch ((i - 3).abs()) { + 0 => 0.72, + 1 => 0.48, + 2 => 0.28, + _ => 0.1, + }, + ), + ), + ), + ), + ], + ), + ); + } +} + +class _TimeSummary extends StatelessWidget { + const _TimeSummary({required this.label, required this.time}); + + final String label; + final String time; + + @override + Widget build(BuildContext context) { + return IdsVStack( + gap: 4, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: [ + IdsText(label, variant: IdsTextVariant.caption), + IdsText(time, variant: IdsTextVariant.body), + ], + ); + } +} + +class _PotgBottomNavigation extends StatelessWidget { + const _PotgBottomNavigation({required this.currentIndex}); + + final int currentIndex; + + @override + Widget build(BuildContext context) { + return IdsBottomNavigation( + currentIndex: currentIndex, + onTap: (_) {}, + items: [ + _navItem(HugeIcons.strokeRoundedHome01, '모든 팟'), + _navItem(HugeIcons.strokeRoundedSearch01, '팟 검색'), + _navItem(HugeIcons.strokeRoundedMessage01, '채팅방'), + _navItem(HugeIcons.strokeRoundedUserCircle02, '내 정보'), + ], + ); + } +} + +class _ZiggleBottomNavigation extends StatelessWidget { + const _ZiggleBottomNavigation({required this.currentIndex}); + + final int currentIndex; + + @override + Widget build(BuildContext context) { + return IdsBottomNavigation( + currentIndex: currentIndex, + onTap: (_) {}, + items: [ + _navItem(HugeIcons.strokeRoundedHome01, '홈'), + _navItem(HugeIcons.strokeRoundedSearch01, '검색'), + _navItem(HugeIcons.strokeRoundedEdit02, '작성'), + _navItem(HugeIcons.strokeRoundedUserCircle02, '내 정보'), + ], + ); + } +} + +class _PotgFloatingButton extends StatelessWidget { + const _PotgFloatingButton(); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: 88), + child: IdsFloatingButton( + semanticLabel: '새 팟 만들기', + onPressed: () {}, + children: const [_HugeIcon(HugeIcons.strokeRoundedCar03)], + ), + ); + } +} + +IdsBottomNavigationItem _navItem(List> icon, String label) { + return IdsBottomNavigationItem( + label: label, + icon: (color, size) => HugeIcon(icon: icon, color: color, size: size), + ); +} + +class _HugeIcon extends StatelessWidget { + const _HugeIcon(this.icon); + + final List> icon; + + @override + Widget build(BuildContext context) { + final iconTheme = IconTheme.of(context); + final theme = ThemeProvider.of(context); + return HugeIcon( + icon: icon, + color: iconTheme.color ?? theme.onSurface, + size: iconTheme.size ?? 24, + ); + } +} diff --git a/packages/flutter/example/lib/main.dart b/packages/flutter/example/lib/main.dart index c3f8fd7..9503e90 100644 --- a/packages/flutter/example/lib/main.dart +++ b/packages/flutter/example/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:ids_flutter/ids.dart'; import 'package:widgetbook/widgetbook.dart'; @@ -9,12 +10,13 @@ import 'components/feedback_usecase.dart'; import 'components/divider_usecase.dart'; import 'components/item_usecase.dart'; import 'components/icon_button_usecase.dart'; +import 'components/mvp_frames_usecase.dart'; import 'components/navigation_usecase.dart'; import 'components/stack_usecase.dart'; import 'components/text_usecase.dart'; void main() { - runApp(const WidgetbookApp()); + runApp(kIsWeb ? const WidgetbookApp() : const MvpFramesApp()); } class WidgetbookApp extends StatelessWidget { @@ -57,6 +59,7 @@ class WidgetbookApp extends StatelessWidget { WidgetbookComponent(name: 'IdsCheckbox', useCases: checkboxUseCases), WidgetbookComponent(name: 'IdsDialog', useCases: dialogUseCases), WidgetbookComponent(name: 'IdsEmpty', useCases: emptyUseCases), + WidgetbookComponent(name: 'MVP Frames', useCases: mvpFrameUseCases), ], ); } diff --git a/packages/flutter/example/pubspec.yaml b/packages/flutter/example/pubspec.yaml index d6d5a3e..41812dc 100644 --- a/packages/flutter/example/pubspec.yaml +++ b/packages/flutter/example/pubspec.yaml @@ -1,6 +1,7 @@ name: ids_flutter_example description: Widgetbook catalog for ids_flutter. publish_to: none +version: 0.0.0+1 environment: sdk: ^3.11.5 @@ -14,6 +15,10 @@ dependencies: widgetbook: ^3.23.0 hugeicons: ^1.1.7 +flutter: + assets: + - assets/mvp/ + dev_dependencies: flutter_test: sdk: flutter diff --git a/packages/flutter/lib/src/components/bottom_navigation/ids_bottom_navigation.dart b/packages/flutter/lib/src/components/bottom_navigation/ids_bottom_navigation.dart index 5dd1d84..a1d8642 100644 --- a/packages/flutter/lib/src/components/bottom_navigation/ids_bottom_navigation.dart +++ b/packages/flutter/lib/src/components/bottom_navigation/ids_bottom_navigation.dart @@ -25,26 +25,30 @@ class IdsBottomNavigation extends StatelessWidget { @override Widget build(BuildContext context) { final theme = ThemeProvider.of(context); + final bottomInset = MediaQuery.paddingOf(context).bottom; + final bottomGap = bottomInset > 20 ? bottomInset - 20 : 8.0; return Container( - height: 72, decoration: BoxDecoration( color: theme.surface, border: Border(top: BorderSide(color: theme.outline)), ), - child: SafeArea( - top: false, - child: Row( - children: [ - for (var i = 0; i < items.length; i++) - Expanded( - child: _IdsBottomNavigationButton( - item: items[i], - active: i == currentIndex, - onTap: () => onTap(i), + child: Padding( + padding: EdgeInsets.only(bottom: bottomGap), + child: SizedBox( + height: 64, + child: Row( + children: [ + for (var i = 0; i < items.length; i++) + Expanded( + child: _IdsBottomNavigationButton( + item: items[i], + active: i == currentIndex, + onTap: () => onTap(i), + ), ), - ), - ], + ], + ), ), ), ); diff --git a/packages/flutter/lib/src/components/button/ids_button.dart b/packages/flutter/lib/src/components/button/ids_button.dart index 1d9634c..fa6c080 100644 --- a/packages/flutter/lib/src/components/button/ids_button.dart +++ b/packages/flutter/lib/src/components/button/ids_button.dart @@ -26,21 +26,30 @@ class IdsButton extends StatelessWidget { final theme = ThemeProvider.of(context); final (bg, fg, border) = switch (variant) { - IdsVariant.solid => (theme.primary, theme.onPrimary, null), - IdsVariant.soft => (theme.secondary, theme.onSecondary, null), - IdsVariant.outline => (null, theme.primary, theme.primary), - IdsVariant.ghost => (null, theme.primary, null), + IdsVariant.solid => (theme.primary, theme.onPrimary, null), + IdsVariant.soft => (theme.secondary, theme.onSecondary, null), + IdsVariant.outline => (null, theme.primary, theme.primary), + IdsVariant.ghost => (null, theme.primary, null), }; final (hPad, textStyle) = switch (size) { - IdsSize.xs => (8.0, IdsTypography.caption), - IdsSize.sm => (10.0, IdsTypography.label), - IdsSize.md => (16.0, IdsTypography.label), - IdsSize.lg => (20.0, IdsTypography.body), - IdsSize.xl => (24.0, IdsTypography.title), + IdsSize.xs => (8.0, IdsTypography.caption), + IdsSize.sm => (10.0, IdsTypography.label), + IdsSize.md => (16.0, IdsTypography.label), + IdsSize.lg => (20.0, IdsTypography.body), + IdsSize.xl => (24.0, IdsTypography.title), IdsSize.xxl => (32.0, IdsTypography.heading), }; + final iconSize = switch (size) { + IdsSize.xs => 16.0, + IdsSize.sm => 18.0, + IdsSize.md => 20.0, + IdsSize.lg => 22.0, + IdsSize.xl => 24.0, + IdsSize.xxl => 28.0, + }; + return GestureDetector( onTap: disabled ? null : onPressed, child: AnimatedOpacity( @@ -61,11 +70,14 @@ class IdsButton extends StatelessWidget { fontWeight: FontWeight.w600, leadingDistribution: TextLeadingDistribution.even, ), - child: IdsHStack( - gap: 8, - fit: IdsStackFit.content, - crossAxis: CrossAxis.center, - children: children, + child: IconTheme( + data: IconThemeData(color: fg, size: iconSize), + child: IdsHStack( + gap: 8, + fit: IdsStackFit.content, + crossAxis: CrossAxis.center, + children: children, + ), ), ), ), diff --git a/packages/flutter/lib/src/components/card/ids_card.dart b/packages/flutter/lib/src/components/card/ids_card.dart index d22f895..9f5e4ad 100644 --- a/packages/flutter/lib/src/components/card/ids_card.dart +++ b/packages/flutter/lib/src/components/card/ids_card.dart @@ -25,9 +25,9 @@ class IdsCard extends StatelessWidget { final bool interactive; double get _radius => switch (size) { - IdsCardSize.sm => 6, - IdsCardSize.md => 8, - IdsCardSize.lg => 12, + IdsCardSize.sm => 10, + IdsCardSize.md => 16, + IdsCardSize.lg => 24, }; @override @@ -43,15 +43,6 @@ class IdsCard extends StatelessWidget { border: variant == IdsCardVariant.outline ? Border.all(color: theme.outline) : null, - boxShadow: variant == IdsCardVariant.elevated - ? [ - BoxShadow( - color: const Color(0xFF000000).withValues(alpha: 0.12), - blurRadius: 16, - offset: const Offset(0, 8), - ), - ] - : null, ); final card = AnimatedContainer( diff --git a/packages/flutter/lib/src/components/dialog/ids_dialog.dart b/packages/flutter/lib/src/components/dialog/ids_dialog.dart index 4a8aa8b..e03eabd 100644 --- a/packages/flutter/lib/src/components/dialog/ids_dialog.dart +++ b/packages/flutter/lib/src/components/dialog/ids_dialog.dart @@ -49,13 +49,6 @@ class IdsDialog extends StatelessWidget { decoration: BoxDecoration( color: theme.surface, borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: const Color(0xFF000000).withValues(alpha: 0.2), - blurRadius: 24, - offset: const Offset(0, 12), - ), - ], ), child: Column( mainAxisSize: MainAxisSize.min, diff --git a/packages/flutter/lib/src/components/empty/ids_empty.dart b/packages/flutter/lib/src/components/empty/ids_empty.dart index 6de365a..ff43674 100644 --- a/packages/flutter/lib/src/components/empty/ids_empty.dart +++ b/packages/flutter/lib/src/components/empty/ids_empty.dart @@ -30,7 +30,7 @@ class IdsEmpty extends StatelessWidget { List _withGaps(List widgets) { return [ for (var i = 0; i < widgets.length; i++) ...[ - if (i > 0) const SizedBox(height: 10), + if (i > 0) SizedBox(height: widgets[i] is IdsEmptyActions ? 18 : 10), widgets[i], ], ]; @@ -82,7 +82,7 @@ class IdsEmptyDescription extends StatelessWidget { final theme = ThemeProvider.of(context); return Text( data, - style: IdsTypography.label.copyWith( + style: IdsTypography.body.copyWith( color: theme.onMuted, leadingDistribution: TextLeadingDistribution.even, ), diff --git a/packages/flutter/lib/src/components/floating_button/ids_floating_button.dart b/packages/flutter/lib/src/components/floating_button/ids_floating_button.dart index 5ce4356..1928aa1 100644 --- a/packages/flutter/lib/src/components/floating_button/ids_floating_button.dart +++ b/packages/flutter/lib/src/components/floating_button/ids_floating_button.dart @@ -74,7 +74,7 @@ class IdsFloatingButton extends StatelessWidget { border: border, boxShadow: [ BoxShadow( - color: const Color(0xFF000000).withValues(alpha: 0.18), + color: const Color(0xFF000000).withValues(alpha: 0.16), blurRadius: 18, offset: const Offset(0, 8), ), diff --git a/packages/react/src/components/card/index.tsx b/packages/react/src/components/card/index.tsx index 3c759a0..4a4a25b 100644 --- a/packages/react/src/components/card/index.tsx +++ b/packages/react/src/components/card/index.tsx @@ -32,7 +32,7 @@ export function Card({ 'bg-(--ids-color-surface) transition-colors', { 'border border-(--ids-color-outline)': variant === 'outline', - 'border border-transparent shadow-lg': variant === 'elevated', + 'border border-transparent': variant === 'elevated', 'border border-transparent bg-(--ids-color-muted)': variant === 'filled', 'border border-transparent bg-transparent': variant === 'ghost', }, diff --git a/packages/react/src/components/dialog/index.tsx b/packages/react/src/components/dialog/index.tsx index 49403f4..cbfbf4f 100644 --- a/packages/react/src/components/dialog/index.tsx +++ b/packages/react/src/components/dialog/index.tsx @@ -46,7 +46,7 @@ export function Dialog({ role={role} aria-modal="true" className={cn( - 'relative w-full rounded-xl bg-(--ids-color-surface) text-(--ids-color-on-surface) shadow-xl', + 'relative w-full rounded-xl bg-(--ids-color-surface) text-(--ids-color-on-surface)', { 'max-w-sm': size === 'sm', 'max-w-md': size === 'md', diff --git a/packages/react/src/components/examples.stories.tsx b/packages/react/src/components/examples.stories.tsx index cb827b6..4f1caf2 100644 --- a/packages/react/src/components/examples.stories.tsx +++ b/packages/react/src/components/examples.stories.tsx @@ -9,6 +9,7 @@ import { UserCircle02Icon, } from 'hugeicons-react'; +import { Avatar } from './avatar'; import { Badge } from './badge'; import { BottomNavigation } from './bottom-navigation'; import { Button } from './button'; @@ -19,6 +20,7 @@ import { Empty } from './empty'; import { FloatingButton } from './floating-button'; import { HStack } from './hstack'; import { IconButton } from './icon-button'; +import { Item } from './item'; import { Tabs } from './tabs'; import { Text } from './text'; @@ -38,6 +40,106 @@ const Phone = ({ children }: { children: ReactNode }) => ( ); +const PhoneHeader = ({ title, backLabel }: { title: string; backLabel?: string }) => ( +
+ {backLabel ? ( + + ) : null} + {title} +
+); + +const PotgNavigation = ({ value }: { value: string }) => ( + + } label="모든 팟" /> + } label="팟 검색" /> + } label="채팅방" /> + } label="내 정보" /> + +); + +const NoticePoster = () => ( +
+ 2024 정보국 +
+ 신규 국원 모집 +
+); + +const NoticeBody = ({ withImage }: { withImage: boolean }) => ( +
+ {withImage ? ( + <> + + + + + Q. Infoteam이 무엇인가요? + + + Infoteam은 IT기술을 이용해 GIST 학생들의 삶을 편리하게 만듭니다. + + + + + ) : null} + + 비상대책위원회 정보국(Infoteam)에서 신규 부원 모집을 진행합니다! +
+ 지원서 작성 구글 폼 링크 +
+ + 인포팀은 IT 서비스 개발을 통해 GIST 학부생의 학교 생활을 편리하게 만들어주는 역할을 수행하고 + 있습니다. 현재 지글(Ziggle), IdP 등의 서비스를 운영 중입니다. + + + 올해 모집은 개발자, 디자이너로 나누어 진행하며 각 직군별 역할을 잘 읽어보신 후 지원해주세요. + +
+); + +const NoticeActions = () => ( +
+ + + + + + +
+); + +const TaxiPotCard = () => ( + +
+ + + 지스트 → 송정역 + + + 13:10~14:00 + + +
+ 정원 + + 1/4 + +
+
+
+); + export const ZiggleGroups: Story = { render: () => ( @@ -91,6 +193,164 @@ export const ZiggleGroups: Story = { ), }; +export const ZiggleNoticeDetailWithImage: Story = { + render: () => ( + + +
+ + + + 인포팀 · 32분 전 + + 2024 정보국 신입 국원 모집 +
+ {['#모집', '#인포팀', '#개발', '#지글', '#비대위', '#정보국'].map((tag) => ( + {tag} + ))} +
+ + +
+
+ ), +}; + +export const ZiggleNoticeDetailTextOnly: Story = { + render: () => ( + + +
+ + + 인포팀 · 32분 전 + + 2024 정보국 신입 국원 모집 +
+ {['#모집', '#인포팀', '#개발', '#지글', '#비대위', '#정보국'].map((tag) => ( + {tag} + ))} +
+ + +
+
+ ), +}; + +export const ZiggleProfile: Story = { + render: () => ( + +
+ + + + + 이정우 + + 20260000 + + crowntheking@gm.gist.ac.kr + + + + + + + + 계정 + 회원 정보 수정 · 아이디 및 비밀번호 변경 + + + + + + + + + 회원 탈퇴 + + +
+ + + 로그아웃 + + + + + + + + + 설정 + 알림 · 언어 · 정보 + + +
+ + + 피드백 · 버그 제보하기 + + + + +
+ + } label="홈" /> + } label="즐겨찾기" /> + } + label="프로필" + /> + + + ), +}; + +export const PotgMainList: Story = { + render: () => ( + +
+ 팟쥐 + + + 요일 별 팟 현황 +
+ {['일', '월', '화', '수', '목', '금', '토'].map((day, index) => ( +
+ {day} + {[0, 1, 2].map((row) => ( +
+ {index === 6 && row === 1 ? 5 : row === 0 ? 0 : 1} +
+ ))} +
+ ))} +
+
+
+ 2025/11/15 토요일 + {Array.from({ length: 5 }, (_, i) => ( + + ))} +
+ + + + +
+ ), +}; + export const PotgSearchEmpty: Story = { render: () => ( @@ -109,12 +369,7 @@ export const PotgSearchEmpty: Story = { - - } label="모든 팟" /> - } label="팟 검색" /> - } label="채팅방" /> - } label="내 정보" /> - + ), }; @@ -166,12 +421,7 @@ export const PotgFilterAndDialog: Story = { - - } label="모든 팟" /> - } label="팟 검색" /> - } label="채팅방" /> - } label="내 정보" /> - + 입장하시겠습니까? @@ -200,3 +450,57 @@ export const PotgFilterAndDialog: Story = { ); }, }; + +export const PotgCreateTime: Story = { + render: () => ( + +
+ 팟 생성 +
+ + + 1 + + 지스트 → 광주송정역 + + + + 2 + + 11월 14일 금요일 + + + + 3 + + 시간대 설정 + +
+ + +
+ 금요일 오전 + 9:41 +
+ ~ +
+ 금요일 오후 + 12:30 +
+
+
+ 출발 가능한 가장 늦은 시각을 설정하세요 + + +
+ 9 + 41 + AM +
+ +
+
+
+
+ ), +};