Browse Source

first commit

ythtc 2 months ago
commit
0f4937b01f
100 changed files with 2194 additions and 0 deletions
  1. 350 0
      VenusKitto.xcodeproj/project.pbxproj
  2. 7 0
      VenusKitto.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  3. BIN
      VenusKitto.xcodeproj/project.xcworkspace/xcuserdata/neoa.xcuserdatad/UserInterfaceState.xcuserstate
  4. 6 0
      VenusKitto.xcodeproj/xcuserdata/neoa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  5. 14 0
      VenusKitto.xcodeproj/xcuserdata/neoa.xcuserdatad/xcschemes/xcschememanagement.plist
  6. 203 0
      VenusKitto/AboutViewController.swift
  7. 961 0
      VenusKitto/AddPetViewController.swift
  8. 36 0
      VenusKitto/AppDelegate.swift
  9. 11 0
      VenusKitto/Assets.xcassets/AccentColor.colorset/Contents.json
  10. BIN
      VenusKitto/Assets.xcassets/AddPet/AddPet383.imageset/AddPet383.png
  11. BIN
      VenusKitto/Assets.xcassets/AddPet/AddPet383.imageset/AddPet383@2x.png
  12. BIN
      VenusKitto/Assets.xcassets/AddPet/AddPet383.imageset/AddPet383@3x.png
  13. 23 0
      VenusKitto/Assets.xcassets/AddPet/AddPet383.imageset/Contents.json
  14. BIN
      VenusKitto/Assets.xcassets/AddPet/AddPet384.imageset/AddPet384.png
  15. 21 0
      VenusKitto/Assets.xcassets/AddPet/AddPet384.imageset/Contents.json
  16. BIN
      VenusKitto/Assets.xcassets/AddPet/AddPet385.imageset/AddPet385.png
  17. 21 0
      VenusKitto/Assets.xcassets/AddPet/AddPet385.imageset/Contents.json
  18. BIN
      VenusKitto/Assets.xcassets/AddPet/AddPet389.imageset/AddPet389.png
  19. BIN
      VenusKitto/Assets.xcassets/AddPet/AddPet389.imageset/AddPet389@2x.png
  20. BIN
      VenusKitto/Assets.xcassets/AddPet/AddPet389.imageset/AddPet389@3x.png
  21. 23 0
      VenusKitto/Assets.xcassets/AddPet/AddPet389.imageset/Contents.json
  22. 6 0
      VenusKitto/Assets.xcassets/AddPet/Contents.json
  23. BIN
      VenusKitto/Assets.xcassets/AddRecord/AddRecord382.imageset/AddRecord382.png
  24. BIN
      VenusKitto/Assets.xcassets/AddRecord/AddRecord382.imageset/AddRecord382@2x.png
  25. BIN
      VenusKitto/Assets.xcassets/AddRecord/AddRecord382.imageset/AddRecord382@3x.png
  26. 23 0
      VenusKitto/Assets.xcassets/AddRecord/AddRecord382.imageset/Contents.json
  27. 6 0
      VenusKitto/Assets.xcassets/AddRecord/Contents.json
  28. 21 0
      VenusKitto/Assets.xcassets/AddRecord/peihead.imageset/Contents.json
  29. BIN
      VenusKitto/Assets.xcassets/AddRecord/peihead.imageset/peihead.png
  30. 38 0
      VenusKitto/Assets.xcassets/AppIcon.appiconset/Contents.json
  31. BIN
      VenusKitto/Assets.xcassets/AppIcon.appiconset/catlogo 2.jpg
  32. BIN
      VenusKitto/Assets.xcassets/AppIcon.appiconset/catlogo 3.jpg
  33. BIN
      VenusKitto/Assets.xcassets/AppIcon.appiconset/catlogo 4.jpg
  34. BIN
      VenusKitto/Assets.xcassets/Bookkeep/Bookkeep395.imageset/Bookkeep395.png
  35. BIN
      VenusKitto/Assets.xcassets/Bookkeep/Bookkeep395.imageset/Bookkeep395@2x.png
  36. BIN
      VenusKitto/Assets.xcassets/Bookkeep/Bookkeep395.imageset/Bookkeep395@3x.png
  37. 23 0
      VenusKitto/Assets.xcassets/Bookkeep/Bookkeep395.imageset/Contents.json
  38. 6 0
      VenusKitto/Assets.xcassets/Bookkeep/Contents.json
  39. 6 0
      VenusKitto/Assets.xcassets/Contents.json
  40. 21 0
      VenusKitto/Assets.xcassets/catlogos.imageset/Contents.json
  41. BIN
      VenusKitto/Assets.xcassets/catlogos.imageset/catlogos.jpg
  42. 6 0
      VenusKitto/Assets.xcassets/home/Contents.json
  43. 23 0
      VenusKitto/Assets.xcassets/home/Home289.imageset/Contents.json
  44. BIN
      VenusKitto/Assets.xcassets/home/Home289.imageset/Home289.png
  45. BIN
      VenusKitto/Assets.xcassets/home/Home289.imageset/Home289@2x.png
  46. BIN
      VenusKitto/Assets.xcassets/home/Home289.imageset/Home289@3x.png
  47. 23 0
      VenusKitto/Assets.xcassets/home/Home290.imageset/Contents.json
  48. BIN
      VenusKitto/Assets.xcassets/home/Home290.imageset/Home290.png
  49. BIN
      VenusKitto/Assets.xcassets/home/Home290.imageset/Home290@2x.png
  50. BIN
      VenusKitto/Assets.xcassets/home/Home290.imageset/Home290@3x.png
  51. 23 0
      VenusKitto/Assets.xcassets/home/Home291.imageset/Contents.json
  52. BIN
      VenusKitto/Assets.xcassets/home/Home291.imageset/Home291.png
  53. BIN
      VenusKitto/Assets.xcassets/home/Home291.imageset/Home291@2x.png
  54. BIN
      VenusKitto/Assets.xcassets/home/Home291.imageset/Home291@3x.png
  55. 23 0
      VenusKitto/Assets.xcassets/home/Home292.imageset/Contents.json
  56. BIN
      VenusKitto/Assets.xcassets/home/Home292.imageset/Home292.png
  57. BIN
      VenusKitto/Assets.xcassets/home/Home292.imageset/Home292@2x.png
  58. BIN
      VenusKitto/Assets.xcassets/home/Home292.imageset/Home292@3x.png
  59. 23 0
      VenusKitto/Assets.xcassets/home/Home293.imageset/Contents.json
  60. BIN
      VenusKitto/Assets.xcassets/home/Home293.imageset/Home293.png
  61. BIN
      VenusKitto/Assets.xcassets/home/Home293.imageset/Home293@2x.png
  62. BIN
      VenusKitto/Assets.xcassets/home/Home293.imageset/Home293@3x.png
  63. 23 0
      VenusKitto/Assets.xcassets/home/Home357.imageset/Contents.json
  64. BIN
      VenusKitto/Assets.xcassets/home/Home357.imageset/Home357.png
  65. BIN
      VenusKitto/Assets.xcassets/home/Home357.imageset/Home357@2x.png
  66. BIN
      VenusKitto/Assets.xcassets/home/Home357.imageset/Home357@3x.png
  67. 23 0
      VenusKitto/Assets.xcassets/home/Home358.imageset/Contents.json
  68. BIN
      VenusKitto/Assets.xcassets/home/Home358.imageset/Home358.png
  69. BIN
      VenusKitto/Assets.xcassets/home/Home358.imageset/Home358@2x.png
  70. BIN
      VenusKitto/Assets.xcassets/home/Home358.imageset/Home358@3x.png
  71. 21 0
      VenusKitto/Assets.xcassets/home/Home359.imageset/Contents.json
  72. BIN
      VenusKitto/Assets.xcassets/home/Home359.imageset/Home359.png
  73. 21 0
      VenusKitto/Assets.xcassets/home/Home360.imageset/Contents.json
  74. BIN
      VenusKitto/Assets.xcassets/home/Home360.imageset/Home360.png
  75. 23 0
      VenusKitto/Assets.xcassets/home/Home361.imageset/Contents.json
  76. BIN
      VenusKitto/Assets.xcassets/home/Home361.imageset/Home361.png
  77. BIN
      VenusKitto/Assets.xcassets/home/Home361.imageset/Home361@2x.png
  78. BIN
      VenusKitto/Assets.xcassets/home/Home361.imageset/Home361@3x.png
  79. 23 0
      VenusKitto/Assets.xcassets/home/Home371.imageset/Contents.json
  80. BIN
      VenusKitto/Assets.xcassets/home/Home371.imageset/Home371.png
  81. BIN
      VenusKitto/Assets.xcassets/home/Home371.imageset/Home371@2x.png
  82. BIN
      VenusKitto/Assets.xcassets/home/Home371.imageset/Home371@3x.png
  83. 23 0
      VenusKitto/Assets.xcassets/home/Home372.imageset/Contents.json
  84. BIN
      VenusKitto/Assets.xcassets/home/Home372.imageset/Home372.png
  85. BIN
      VenusKitto/Assets.xcassets/home/Home372.imageset/Home372@2x.png
  86. BIN
      VenusKitto/Assets.xcassets/home/Home372.imageset/Home372@3x.png
  87. 23 0
      VenusKitto/Assets.xcassets/home/Home373.imageset/Contents.json
  88. BIN
      VenusKitto/Assets.xcassets/home/Home373.imageset/Home373.png
  89. BIN
      VenusKitto/Assets.xcassets/home/Home373.imageset/Home373@2x.png
  90. BIN
      VenusKitto/Assets.xcassets/home/Home373.imageset/Home373@3x.png
  91. 23 0
      VenusKitto/Assets.xcassets/home/Home374.imageset/Contents.json
  92. BIN
      VenusKitto/Assets.xcassets/home/Home374.imageset/Home374.png
  93. BIN
      VenusKitto/Assets.xcassets/home/Home374.imageset/Home374@2x.png
  94. BIN
      VenusKitto/Assets.xcassets/home/Home374.imageset/Home374@3x.png
  95. 23 0
      VenusKitto/Assets.xcassets/home/Home375.imageset/Contents.json
  96. BIN
      VenusKitto/Assets.xcassets/home/Home375.imageset/Home375.png
  97. BIN
      VenusKitto/Assets.xcassets/home/Home375.imageset/Home375@2x.png
  98. BIN
      VenusKitto/Assets.xcassets/home/Home375.imageset/Home375@3x.png
  99. 21 0
      VenusKitto/Assets.xcassets/home/Home377.imageset/Contents.json
  100. BIN
      VenusKitto/Assets.xcassets/home/Home377.imageset/Home377@3x.png

+ 350 - 0
VenusKitto.xcodeproj/project.pbxproj

@@ -0,0 +1,350 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 77;
+	objects = {
+
+/* Begin PBXFileReference section */
+		B5EE3FE52E56FEAB00E519E8 /* VenusKitto.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VenusKitto.app; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
+		B5EE3FF72E56FEAC00E519E8 /* Exceptions for "VenusKitto" folder in "VenusKitto" target */ = {
+			isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+			membershipExceptions = (
+				Info.plist,
+			);
+			target = B5EE3FE42E56FEAB00E519E8 /* VenusKitto */;
+		};
+/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
+
+/* Begin PBXFileSystemSynchronizedRootGroup section */
+		B5EE3FE72E56FEAB00E519E8 /* VenusKitto */ = {
+			isa = PBXFileSystemSynchronizedRootGroup;
+			exceptions = (
+				B5EE3FF72E56FEAC00E519E8 /* Exceptions for "VenusKitto" folder in "VenusKitto" target */,
+			);
+			path = VenusKitto;
+			sourceTree = "<group>";
+		};
+/* End PBXFileSystemSynchronizedRootGroup section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		B5EE3FE22E56FEAB00E519E8 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		B5EE3FDC2E56FEAB00E519E8 = {
+			isa = PBXGroup;
+			children = (
+				B5EE3FE72E56FEAB00E519E8 /* VenusKitto */,
+				B5EE3FE62E56FEAB00E519E8 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		B5EE3FE62E56FEAB00E519E8 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				B5EE3FE52E56FEAB00E519E8 /* VenusKitto.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		B5EE3FE42E56FEAB00E519E8 /* VenusKitto */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = B5EE3FF82E56FEAC00E519E8 /* Build configuration list for PBXNativeTarget "VenusKitto" */;
+			buildPhases = (
+				B5EE3FE12E56FEAB00E519E8 /* Sources */,
+				B5EE3FE22E56FEAB00E519E8 /* Frameworks */,
+				B5EE3FE32E56FEAB00E519E8 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			fileSystemSynchronizedGroups = (
+				B5EE3FE72E56FEAB00E519E8 /* VenusKitto */,
+			);
+			name = VenusKitto;
+			packageProductDependencies = (
+			);
+			productName = VenusKitto;
+			productReference = B5EE3FE52E56FEAB00E519E8 /* VenusKitto.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		B5EE3FDD2E56FEAB00E519E8 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				BuildIndependentTargetsInParallel = 1;
+				LastSwiftUpdateCheck = 1640;
+				LastUpgradeCheck = 1640;
+				TargetAttributes = {
+					B5EE3FE42E56FEAB00E519E8 = {
+						CreatedOnToolsVersion = 16.4;
+					};
+				};
+			};
+			buildConfigurationList = B5EE3FE02E56FEAB00E519E8 /* Build configuration list for PBXProject "VenusKitto" */;
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = B5EE3FDC2E56FEAB00E519E8;
+			minimizedProjectReferenceProxies = 1;
+			preferredProjectObjectVersion = 77;
+			productRefGroup = B5EE3FE62E56FEAB00E519E8 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				B5EE3FE42E56FEAB00E519E8 /* VenusKitto */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		B5EE3FE32E56FEAB00E519E8 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		B5EE3FE12E56FEAB00E519E8 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		B5EE3FF92E56FEAC00E519E8 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 2;
+				DEVELOPMENT_TEAM = 5PR42TKKTT;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = VenusKitto/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = "咕噜日记";
+				INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
+				INFOPLIST_KEY_NSCameraUsageDescription = "咕噜日记需要访问您的相机来拍摄头像照片";
+				INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "咕噜日记需要访问您的相册来选择头像照片";
+				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+				INFOPLIST_KEY_UIMainStoryboardFile = Main;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.ytwl.glrj;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		B5EE3FFA2E56FEAC00E519E8 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 2;
+				DEVELOPMENT_TEAM = 5PR42TKKTT;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = VenusKitto/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = "咕噜日记";
+				INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
+				INFOPLIST_KEY_NSCameraUsageDescription = "咕噜日记需要访问您的相机来拍摄头像照片";
+				INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "咕噜日记需要访问您的相册来选择头像照片";
+				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+				INFOPLIST_KEY_UIMainStoryboardFile = Main;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.ytwl.glrj;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+		B5EE3FFB2E56FEAC00E519E8 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES;
+				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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				ENABLE_USER_SCRIPT_SANDBOXING = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu17;
+				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 = 18.5;
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+			};
+			name = Debug;
+		};
+		B5EE3FFC2E56FEAC00E519E8 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES;
+				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_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_USER_SCRIPT_SANDBOXING = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu17;
+				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 = 18.5;
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				SDKROOT = iphoneos;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		B5EE3FE02E56FEAB00E519E8 /* Build configuration list for PBXProject "VenusKitto" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				B5EE3FFB2E56FEAC00E519E8 /* Debug */,
+				B5EE3FFC2E56FEAC00E519E8 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		B5EE3FF82E56FEAC00E519E8 /* Build configuration list for PBXNativeTarget "VenusKitto" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				B5EE3FF92E56FEAC00E519E8 /* Debug */,
+				B5EE3FFA2E56FEAC00E519E8 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = B5EE3FDD2E56FEAB00E519E8 /* Project object */;
+}

+ 7 - 0
VenusKitto.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:">
+   </FileRef>
+</Workspace>

BIN
VenusKitto.xcodeproj/project.xcworkspace/xcuserdata/neoa.xcuserdatad/UserInterfaceState.xcuserstate


+ 6 - 0
VenusKitto.xcodeproj/xcuserdata/neoa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Bucket
+   uuid = "F2C03992-8706-4645-B863-F05F4BAF5F75"
+   type = "1"
+   version = "2.0">
+</Bucket>

+ 14 - 0
VenusKitto.xcodeproj/xcuserdata/neoa.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>SchemeUserState</key>
+	<dict>
+		<key>VenusKitto.xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>0</integer>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 203 - 0
VenusKitto/AboutViewController.swift

@@ -0,0 +1,203 @@
+//
+//  AboutViewController.swift
+//  VenusKitto
+//
+//  Created by Neoa on 2025/8/27.
+//
+
+import UIKit
+import WebKit
+
+final class AboutViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
+
+    // 可按需替换为你们的线上链接
+    private let PRIVACY_URL = URL(string: "https://ytwljs.github.io/gl-policy.html")!
+    private let TERMS_URL   = URL(string: "https://ytwljs.github.io/gl-user.html")!
+
+    private let titleLabel: UILabel = {
+        let l = UILabel()
+        l.text = "关于我们"
+        l.font = .systemFont(ofSize: 28, weight: .semibold)
+        l.textColor = UIColor(hex: "#2B2B2B")
+        return l
+    }()
+
+    private let logoImageView: UIImageView = {
+        let iv = UIImageView(image: UIImage(named: "Home372"))
+        iv.contentMode = .scaleAspectFit
+        iv.clipsToBounds = true
+        iv.layer.cornerRadius = 20
+        return iv
+    }()
+
+    private let versionLabel: UILabel = {
+        let l = UILabel()
+        l.font = .systemFont(ofSize: 14)
+        l.textColor = UIColor(hex: "#888888")
+        l.textAlignment = .center
+        return l
+    }()
+
+    private let tableView: UITableView = {
+        let tv = UITableView(frame: .zero, style: .insetGrouped)
+        tv.backgroundColor = .clear
+        tv.showsVerticalScrollIndicator = false
+        tv.separatorInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
+        return tv
+    }()
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        view.backgroundColor = UIColor(hex: "#FFFEFC")
+        
+        if let backImage = UIImage(named: "AddPet385") {
+            let backButton = UIBarButtonItem(image: backImage.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(tapCancel))
+            navigationItem.leftBarButtonItem = backButton
+        }
+
+        buildUI()
+        fillInfo()
+        tableView.dataSource = self
+        tableView.delegate = self
+    }
+
+    private func buildUI() {
+        view.addSubview(titleLabel)
+        titleLabel.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12),
+            titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24)
+        ])
+
+        // 中心内容
+        let centerWrap = UIView()
+        view.addSubview(centerWrap)
+        centerWrap.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            centerWrap.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 24),
+            centerWrap.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24),
+            centerWrap.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24)
+        ])
+
+        centerWrap.addSubview(logoImageView)
+        centerWrap.addSubview(versionLabel)
+        logoImageView.translatesAutoresizingMaskIntoConstraints = false
+        versionLabel.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            logoImageView.topAnchor.constraint(equalTo: centerWrap.topAnchor, constant: 24),
+            logoImageView.centerXAnchor.constraint(equalTo: centerWrap.centerXAnchor),
+            logoImageView.widthAnchor.constraint(equalToConstant: 80),
+            logoImageView.heightAnchor.constraint(equalToConstant: 80),
+
+            versionLabel.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: 8),
+            versionLabel.centerXAnchor.constraint(equalTo: centerWrap.centerXAnchor),
+            versionLabel.bottomAnchor.constraint(equalTo: centerWrap.bottomAnchor)
+        ])
+
+        view.addSubview(tableView)
+        tableView.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            tableView.topAnchor.constraint(equalTo: centerWrap.bottomAnchor, constant: 24),
+            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
+        ])
+    }
+    
+    @objc private func tapCancel() { navigationController?.popViewController(animated: true)
+    }
+
+
+    private func fillInfo() {
+        let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "-"
+        versionLabel.text = "版本 v\(version)"
+    }
+
+    // MARK: - UITableViewDataSource
+    func numberOfSections(in tableView: UITableView) -> Int { 1 }
+
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 2 }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        let identifier = "PolicyCell"
+        let cell = tableView.dequeueReusableCell(withIdentifier: identifier) ??
+                   UITableViewCell(style: .default, reuseIdentifier: identifier)
+        cell.accessoryType = .disclosureIndicator
+        cell.selectionStyle = .default
+        cell.textLabel?.font = .systemFont(ofSize: 16, weight: .regular)
+        cell.textLabel?.textColor = UIColor(hex: "#2B2B2B")
+        cell.backgroundColor = .white
+        cell.contentView.backgroundColor = .white
+
+        cell.textLabel?.text = (indexPath.row == 0) ? "隐私协议" : "用户协议"
+        return cell
+    }
+
+    // MARK: - UITableViewDelegate
+    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 52 }
+
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        tableView.deselectRow(at: indexPath, animated: true)
+        let isPrivacy = (indexPath.row == 0)
+        let url = isPrivacy ? PRIVACY_URL : TERMS_URL
+        let title = isPrivacy ? "隐私协议" : "用户协议"
+        let vc = PolicyWebController(url: url, titleText: title)
+        vc.hidesBottomBarWhenPushed = true
+        navigationController?.pushViewController(vc, animated: true)
+    }
+}
+
+// 简易内置 Web 容器
+final class PolicyWebController: UIViewController, WKNavigationDelegate {
+    private let url: URL
+    private let titleText: String
+    private var webView: WKWebView!
+
+    init(url: URL, titleText: String) {
+        self.url = url
+        self.titleText = titleText
+        super.init(nibName: nil, bundle: nil)
+    }
+
+    required init?(coder: NSCoder) { fatalError() }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        view.backgroundColor = UIColor(hex: "#FFFEFC")
+
+        if let backImage = UIImage(named: "AddPet385") {
+            let backButton = UIBarButtonItem(image: backImage.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(tapCancel))
+            navigationItem.leftBarButtonItem = backButton
+        }
+
+        
+        let titleLabel = UILabel()
+        titleLabel.text = titleText
+        titleLabel.font = .systemFont(ofSize: 20, weight: .semibold)
+        titleLabel.textColor = UIColor(hex: "#2B2B2B")
+
+        view.addSubview(titleLabel)
+        titleLabel.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8),
+            titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
+        ])
+
+        webView = WKWebView(frame: .zero)
+        webView.navigationDelegate = self
+        view.addSubview(webView)
+        webView.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            webView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8),
+            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
+        ])
+
+        webView.load(URLRequest(url: url))
+    }
+    
+    @objc private func tapCancel() { navigationController?.popViewController(animated: true)
+    }
+
+}

+ 961 - 0
VenusKitto/AddPetViewController.swift

@@ -0,0 +1,961 @@
+//
+//  AddPetViewController.swift
+//  VenusKitto
+//
+//  Created by Neoa on 2025/8/22.
+//
+
+import Foundation
+import UIKit
+
+// MARK: - AddPetViewController (添加宠物)
+final class AddPetViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
+
+    private let scrollView = UIScrollView()
+    private let contentView = UIView()
+
+    private let avatarButton = UIButton(type: .custom)
+    private let avatarHint = UILabel()
+
+    private let nickCard = UIView()
+    private let nickTitle = UILabel()
+    private let nickField = UITextField()
+
+    private let infoCard = UIView()
+
+    // rows
+    private let weightRow = InputRow(title: "体重", placeholder: "请输入体重(kg)", showsChevron: false, keyboard: .decimalPad)
+    private let speciesRow = SelectRow(title: "种类")
+    private let breedRow   = SelectRow(title: "品种")
+    private let genderRow  = SelectRow(title: "性别")
+    private let birthRow   = SelectRow(title: "出生日期")
+    private let arriveRow  = SelectRow(title: "到家日期")
+
+    private let cancelBtn = UIButton(type: .system)
+    private let confirmBtn = UIButton(type: .system)
+
+    private var selectedSpecies: String?
+    private var selectedBreed: String? // For display (breed name)
+    private var selectedBreedId: String? // For storing breedId
+    private var selectedGender: String?
+    private var birthDate: Date?
+    private var arriveDate: Date?
+    // For avatar upload
+    private var avatarImageUrl: String?
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        view.backgroundColor = .white
+        title = "添加宠物"
+        // Set custom back button image without text or back label
+        if let backImage = UIImage(named: "AddPet385") {
+            let backButton = UIBarButtonItem(image: backImage.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(tapCancel))
+            navigationItem.leftBarButtonItem = backButton
+        }
+        layout()
+        wire()
+    }
+
+    private func layout() {
+        // scroll
+        view.addSubview(scrollView)
+        scrollView.translatesAutoresizingMaskIntoConstraints = false
+        scrollView.showsVerticalScrollIndicator = false
+        scrollView.keyboardDismissMode = .onDrag
+        scrollView.addSubview(contentView)
+        contentView.translatesAutoresizingMaskIntoConstraints = false
+
+        NSLayoutConstraint.activate([
+            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
+            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
+
+            contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
+            contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
+            contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
+            contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
+            contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
+        ])
+
+        // avatar
+        avatarButton.translatesAutoresizingMaskIntoConstraints = false
+        avatarButton.setImage(UIImage(named: "Home372") ?? UIImage(systemName: "pawprint.circle")!, for: .normal)
+        avatarButton.imageView?.contentMode = .scaleAspectFill
+        avatarButton.layer.cornerRadius = 40
+        avatarButton.clipsToBounds = true
+        avatarButton.backgroundColor = UIColor(hex: "#FFF3D9")
+
+        avatarHint.text = "点击上传头像"
+        avatarHint.font = .systemFont(ofSize: 12)
+        avatarHint.textColor = UIColor(hex: "#8B8B8B")
+        avatarHint.textAlignment = .center
+        avatarHint.translatesAutoresizingMaskIntoConstraints = false
+
+        contentView.addSubview(avatarButton)
+        contentView.addSubview(avatarHint)
+
+        NSLayoutConstraint.activate([
+            avatarButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16),
+            avatarButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 24),
+            avatarButton.widthAnchor.constraint(equalToConstant: 80),
+            avatarButton.heightAnchor.constraint(equalToConstant: 80),
+
+            avatarHint.topAnchor.constraint(equalTo: avatarButton.bottomAnchor, constant: 6),
+            avatarHint.centerXAnchor.constraint(equalTo: avatarButton.centerXAnchor)
+        ])
+
+        // Nick card
+        nickCard.backgroundColor = .white
+        nickCard.layer.cornerRadius = 12
+        nickCard.layer.shadowColor = UIColor.black.cgColor
+        nickCard.layer.shadowOpacity = 0.06
+        nickCard.layer.shadowRadius = 6
+        nickCard.layer.shadowOffset = .init(width: 0, height: 2)
+        nickCard.translatesAutoresizingMaskIntoConstraints = false
+
+        nickTitle.text = "昵称"
+        nickTitle.font = .systemFont(ofSize: 14)
+        nickTitle.textColor = UIColor(hex: "#5B5B5B")
+        nickField.placeholder = "请输入昵称"
+        nickField.font = .systemFont(ofSize: 14)
+        nickField.textAlignment = .right
+        nickField.clearButtonMode = .whileEditing
+
+        let nickSeparator = DashedSeparator()
+
+        [nickTitle, nickField].forEach { nickCard.addSubview($0); $0.translatesAutoresizingMaskIntoConstraints = false }
+        contentView.addSubview(nickCard)
+
+        NSLayoutConstraint.activate([
+            nickCard.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 120),
+            nickCard.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 24),
+            nickCard.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -24),
+            nickCard.heightAnchor.constraint(equalToConstant: 64),
+
+            nickTitle.centerYAnchor.constraint(equalTo: nickCard.centerYAnchor),
+            nickTitle.leadingAnchor.constraint(equalTo: nickCard.leadingAnchor, constant: 16),
+
+            nickField.centerYAnchor.constraint(equalTo: nickCard.centerYAnchor),
+            nickField.trailingAnchor.constraint(equalTo: nickCard.trailingAnchor, constant: -24),
+            nickField.leadingAnchor.constraint(greaterThanOrEqualTo: nickTitle.trailingAnchor, constant: 12)
+        ])
+
+        // Info card
+        infoCard.backgroundColor = .white
+        infoCard.layer.cornerRadius = 12
+        infoCard.layer.shadowColor = UIColor.black.cgColor
+        infoCard.layer.shadowOpacity = 0.06
+        infoCard.layer.shadowRadius = 6
+        infoCard.layer.shadowOffset = .init(width: 0, height: 2)
+        infoCard.translatesAutoresizingMaskIntoConstraints = false
+        contentView.addSubview(infoCard)
+
+        let rows: [UIView] = [weightRow, speciesRow, breedRow, genderRow, birthRow, arriveRow]
+        rows.forEach { r in
+            r.translatesAutoresizingMaskIntoConstraints = false
+            infoCard.addSubview(r)
+        }
+        // separators
+        let seps = (0..<(rows.count-1)).map { _ in DashedSeparator() }
+        seps.forEach { s in infoCard.addSubview(s); s.translatesAutoresizingMaskIntoConstraints = false }
+
+        NSLayoutConstraint.activate([
+            infoCard.topAnchor.constraint(equalTo: nickCard.bottomAnchor, constant: 16),
+            infoCard.leadingAnchor.constraint(equalTo: nickCard.leadingAnchor),
+            infoCard.trailingAnchor.constraint(equalTo: nickCard.trailingAnchor)
+        ])
+
+        // Row heights
+        let h: CGFloat = 52
+        var prev: UIView? = nil
+        for (idx, row) in rows.enumerated() {
+            NSLayoutConstraint.activate([
+                row.leadingAnchor.constraint(equalTo: infoCard.leadingAnchor, constant: 12),
+                row.trailingAnchor.constraint(equalTo: infoCard.trailingAnchor, constant: -12),
+                row.heightAnchor.constraint(equalToConstant: h)
+            ])
+            if let p = prev {
+                row.topAnchor.constraint(equalTo: p.bottomAnchor).isActive = true
+            } else {
+                row.topAnchor.constraint(equalTo: infoCard.topAnchor).isActive = true
+            }
+            if idx < seps.count {
+                let sep = seps[idx]
+                NSLayoutConstraint.activate([
+                    sep.leadingAnchor.constraint(equalTo: infoCard.leadingAnchor, constant: 12),
+                    sep.trailingAnchor.constraint(equalTo: infoCard.trailingAnchor, constant: -12),
+                    sep.topAnchor.constraint(equalTo: row.bottomAnchor),
+                    sep.heightAnchor.constraint(equalToConstant: 1)
+                ])
+            }
+            prev = row
+        }
+        prev!.bottomAnchor.constraint(equalTo: infoCard.bottomAnchor).isActive = true
+
+        // Bottom buttons
+        cancelBtn.setTitle("取消", for: .normal)
+        cancelBtn.setTitleColor(.white, for: .normal)
+        cancelBtn.backgroundColor = UIColor(hex: "#CFC7BD")
+        cancelBtn.layer.cornerRadius = 22
+
+        confirmBtn.setTitle("确定", for: .normal)
+        confirmBtn.setTitleColor(.black, for: .normal)
+        confirmBtn.backgroundColor = UIColor(hex: "#FFE059")
+        confirmBtn.layer.cornerRadius = 22
+
+        [cancelBtn, confirmBtn].forEach { v in
+            contentView.addSubview(v)
+            v.translatesAutoresizingMaskIntoConstraints = false
+            v.heightAnchor.constraint(equalToConstant: 44).isActive = true
+        }
+
+        NSLayoutConstraint.activate([
+            cancelBtn.topAnchor.constraint(equalTo: infoCard.bottomAnchor, constant: 28),
+            cancelBtn.leadingAnchor.constraint(equalTo: infoCard.leadingAnchor),
+            cancelBtn.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant: -8),
+
+            confirmBtn.topAnchor.constraint(equalTo: cancelBtn.topAnchor),
+            confirmBtn.leadingAnchor.constraint(equalTo: view.centerXAnchor, constant: 8),
+            confirmBtn.trailingAnchor.constraint(equalTo: infoCard.trailingAnchor),
+            confirmBtn.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -28)
+        ])
+    }
+
+    private func wire() {
+        let tap = UITapGestureRecognizer(target: self, action: #selector(endEdit))
+        tap.cancelsTouchesInView = false
+        view.addGestureRecognizer(tap)
+
+        avatarButton.addTarget(self, action: #selector(pickAvatar), for: .touchUpInside)
+        cancelBtn.addTarget(self, action: #selector(tapCancel), for: .touchUpInside)
+        confirmBtn.addTarget(self, action: #selector(tapConfirm), for: .touchUpInside)
+
+        speciesRow.onTap = { [weak self] in self?.chooseSpecies() }
+        breedRow.onTap   = { [weak self] in self?.chooseBreed() }
+        genderRow.onTap  = { [weak self] in self?.chooseGender() }
+        birthRow.onTap   = { [weak self] in self?.chooseDate(for: .birth) }
+        arriveRow.onTap  = { [weak self] in self?.chooseDate(for: .arrive) }
+    }
+
+    @objc private func endEdit() { view.endEditing(true) }
+
+    // MARK: - Actions
+    // Upload avatar image
+    @objc private func pickAvatar() {
+        let picker = UIImagePickerController()
+        picker.sourceType = .photoLibrary
+        picker.delegate = self
+        present(picker, animated: true)
+    }
+
+    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
+        if let img = info[.originalImage] as? UIImage {
+            avatarButton.setImage(img, for: .normal)
+            uploadAvatar(image: img) // Upload avatar after picking
+        }
+        picker.dismiss(animated: true)
+    }
+
+    private func uploadAvatar(image: UIImage) {
+        guard let imageData = image.jpegData(compressionQuality: 0.7) else { return }
+        let url = URL(string: "\(baseURL)/common/upload")!
+        var request = URLRequest(url: url)
+        request.httpMethod = "POST"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        if let token = UserDefaults.standard.string(forKey: "userToken") {
+            request.setValue(token, forHTTPHeaderField: "Authorization")
+        }
+
+        // 创建多部分表单数据
+        let boundary = "Boundary-\(UUID().uuidString)"
+        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
+        
+        var body = Data()
+        
+        // 添加图片数据
+        body.append("--\(boundary)\r\n".data(using: .utf8)!)
+        body.append("Content-Disposition: form-data; name=\"file\"; filename=\"avatar.jpg\"\r\n".data(using: .utf8)!)
+        body.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
+        body.append(imageData)
+        body.append("\r\n".data(using: .utf8)!)
+        
+        // 结束边界
+        body.append("--\(boundary)--\r\n".data(using: .utf8)!)
+
+        request.httpBody = body
+
+        let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
+            if let error = error {
+                print("Error uploading image: \(error)")
+                DispatchQueue.main.async {
+                    self?.showToast(message: "头像上传失败,请重试。")
+                }
+                return
+            }
+            guard let data = data else {
+                DispatchQueue.main.async {
+                    self?.showToast(message: "头像上传失败,请重试。")
+                }
+                return
+            }
+
+            do {
+                let decoder = JSONDecoder()
+                let responseObject = try decoder.decode(UploadImageResponse.self, from: data)
+                if responseObject.code == "200" {
+                    // Get imageUrl and save it
+                    self?.avatarImageUrl = responseObject.data.url
+                    print("ssss \(String(describing: self?.avatarImageUrl))")
+                    DispatchQueue.main.async {
+                        self?.showToast(message: "头像上传成功!")
+                    }
+                } else {
+                    print("Error: \(responseObject.msg ?? "Unknown error")")
+                    DispatchQueue.main.async {
+                        self?.showToast(message: "头像上传失败,请重试。")
+                    }
+                }
+            } catch {
+                print("Error decoding upload response: \(error)")
+                DispatchQueue.main.async {
+                    self?.showToast(message: "头像上传失败,请重试。")
+                }
+            }
+
+        }
+        task.resume()
+    }
+
+    @objc private func tapCancel() { navigationController?.popViewController(animated: true) }
+
+    @objc private func tapConfirm() {
+        // Fetch breedId from selectedBreedId and categoryId from selectedSpecies
+        let breedId = Int(selectedBreedId ?? "") ?? 0
+        let categoryId = getCategoryId(from: selectedSpecies)
+        let userId = UserDefaults.standard.integer(forKey: "userId") // Fetch userId from UserDefaults (or other storage)
+
+        // DateFormatter to format the dates in the desired format
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "yyyy-MM-dd"
+
+        // Format the arrivalDate and birthDate
+        let formattedArrivalDate = dateFormatter.string(from: arriveDate ?? Date())
+        let formattedBirthDate = dateFormatter.string(from: birthDate ?? Date())
+
+        // Collect other data for pet save
+        let name = nickField.text ?? ""
+        let weight = weightRow.text
+        let petData = PetSaveRequest(
+            arrivalDate: formattedArrivalDate,
+            avatar: avatarImageUrl ?? "",
+            birthDate: formattedBirthDate,
+            breedId: breedId,
+            categoryId: categoryId,
+            createTime: "",
+            gender: selectedGender ?? "",
+            id: 0,
+            name: name,
+            nickname: nickField.text ?? "",
+            updateTime: "",
+            userId: userId,
+            weight: Double(weight ?? "0") ?? 0
+        )
+        print("dkkd \(petData)")
+        savePetData(petData)
+    }
+
+    // Helper methods to get categoryId
+
+    private func getCategoryId(from species: String?) -> Int {
+        // Replace with actual logic to fetch categoryId based on species
+        switch species {
+        case "狗": return 3
+        case "猫": return 4
+        default: return 0
+        }
+    }
+
+    private func savePetData(_ petData: PetSaveRequest) {
+        guard let url = URL(string: "\(baseURL)/petRecordPet/petSave") else { return }
+        var request = URLRequest(url: url)
+        request.httpMethod = "POST"
+        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+        if let token = UserDefaults.standard.string(forKey: "userToken") {
+            request.setValue(token, forHTTPHeaderField: "Authorization")
+        }
+
+        do {
+            let encoder = JSONEncoder()
+            let body = try encoder.encode(petData)
+            request.httpBody = body
+        } catch {
+            print("Error encoding pet data: \(error)")
+            DispatchQueue.main.async {
+                self.showToast(message: "宠物信息保存失败,请重试。")
+            }
+            return
+        }
+
+        let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
+            if let error = error {
+                print("Error saving pet: \(error)")
+                DispatchQueue.main.async {
+                    self?.showToast(message: "宠物信息保存失败,请重试。")
+                }
+                return
+            }
+            guard let data = data else {
+                DispatchQueue.main.async {
+                    self?.showToast(message: "宠物信息保存失败,请重试。")
+                }
+                return
+            }
+
+            do {
+                if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
+                    if let code = json["code"] as? String, code != "500" {
+                        print("Pet saved successfully!")
+                        // 通知首页刷新宠物列表
+                        let uidStr = UserDefaults.standard.string(forKey: "userId") ?? {
+                            let v = UserDefaults.standard.integer(forKey: "userId"); return v == 0 ? "" : String(v)
+                        }()
+                        NotificationCenter.default.post(name: .petDidSave, object: nil, userInfo: ["userId": uidStr])
+                        DispatchQueue.main.async {
+                            self?.showToast(message: "宠物信息保存成功!")
+                        }
+                        // Add delay of 1.5 seconds before going back
+                        DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in
+                            self?.navigationController?.popViewController(animated: true)
+                        }
+                    } else {
+                        DispatchQueue.main.async {
+                            self?.showToast(message: "宠物信息保存失败,请重试。")
+                        }
+                    }
+                }
+            } catch {
+                print("Error decoding pet save response: \(error)")
+                // 通知首页刷新宠物列表(异常也发通知)
+                let uidStr = UserDefaults.standard.string(forKey: "userId") ?? {
+                    let v = UserDefaults.standard.integer(forKey: "userId"); return v == 0 ? "" : String(v)
+                }()
+                NotificationCenter.default.post(name: .petDidSave, object: nil, userInfo: ["userId": uidStr])
+                DispatchQueue.main.async {
+                    self?.showToast(message: "宠物信息保存成功!")
+                }
+                DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in
+                    self?.navigationController?.popViewController(animated: true)
+                }
+            }
+        }
+        task.resume()
+    }
+
+    // MARK: - Present action sheet safely on iPad
+    private func presentSheet(_ ac: UIAlertController, from source: UIView) {
+        if let pop = ac.popoverPresentationController {
+            // 优先用触发的控件作为锚点
+            if source.window != nil {
+                pop.sourceView = source
+                pop.sourceRect = source.bounds
+                pop.permittedArrowDirections = [.up, .down]
+            } else {
+                // 兜底:用整个视图中心作为锚点(极少数情况下 source 还未在窗口层级里)
+                pop.sourceView = self.view
+                pop.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 1, height: 1)
+                pop.permittedArrowDirections = []
+            }
+        }
+        self.present(ac, animated: true)
+    }
+    
+    // MARK: - Toast
+    private func showToast(message: String) {
+        let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width / 2 - 150, y: self.view.frame.size.height/2 - 50, width: 300, height: 50))
+        toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.7)
+        toastLabel.textColor = UIColor.white
+        toastLabel.textAlignment = .center
+        toastLabel.font = .systemFont(ofSize: 14)
+        toastLabel.text = message
+        toastLabel.alpha = 1.0
+        toastLabel.layer.cornerRadius = 10
+        toastLabel.clipsToBounds  =  true
+        self.view.addSubview(toastLabel)
+
+        UIView.animate(withDuration: 1, delay: 1, options: .curveEaseOut, animations: {
+            toastLabel.alpha = 0.0
+        }, completion: { _ in
+            toastLabel.removeFromSuperview()
+        })
+    }
+
+    // Models for requests and responses
+    struct UploadImageResponse: Codable {
+        let code: String
+        let msg: String?
+        let data: UploadImageData
+    }
+
+    struct UploadImageData: Codable {
+        let url: String
+    }
+
+    struct PetSaveRequest: Codable {
+        let arrivalDate: String
+        let avatar: String
+        let birthDate: String
+        let breedId: Int
+        let categoryId: Int
+        let createTime: String
+        let gender: String
+        let id: Int
+        let name: String
+        let nickname: String
+        let updateTime: String
+        let userId: Int
+        let weight: Double
+    }
+
+    struct PetSaveResponse: Codable {
+        let code: String
+        let msg: String?
+        let data: PetSaveData?
+    }
+
+    struct PetSaveData: Codable {
+        let petId: Int
+    }
+
+    private func chooseSpecies() {
+        let ac = UIAlertController(title: "选择种类", message: nil, preferredStyle: .actionSheet)
+        ["猫", "狗"].forEach { t in ac.addAction(UIAlertAction(title: t, style: .default, handler: { _ in
+            self.selectedSpecies = t
+            self.speciesRow.value = t
+            // 清空品种
+            self.selectedBreed = nil
+            self.selectedBreedId = nil
+            self.breedRow.value = "请选择"
+        })) }
+        ac.addAction(UIAlertAction(title: "取消", style: .cancel))
+        // ✅ 关键:指定 popover 锚点
+        presentSheet(ac, from: self.speciesRow)
+    }
+
+    private func chooseBreed() {
+        guard let sp = selectedSpecies else {
+            let ac = UIAlertController(title: "请先选择种类", message: nil, preferredStyle: .alert)
+            ac.addAction(UIAlertAction(title: "确定", style: .default))
+            present(ac, animated: true); return
+        }
+        let categoryId: Int
+        switch sp {
+        case "狗": categoryId = 3
+        case "猫": categoryId = 4
+        default: categoryId = 0
+        }
+        let vc = BreedPickerViewController(categoryId: categoryId, token: UserDefaults.standard.string(forKey: "userToken"))
+        vc.onSelect = { [weak self] breedId, breedName in
+            self?.selectedBreed = breedName
+            self?.breedRow.value = breedName
+            self?.selectedBreedId = breedId
+            self?.navigationController?.popViewController(animated: true)
+        }
+        navigationController?.pushViewController(vc, animated: true)
+    }
+
+    private func chooseGender() {
+        let ac = UIAlertController(title: "选择性别", message: nil, preferredStyle: .actionSheet)
+        ["公", "母"].forEach { t in ac.addAction(UIAlertAction(title: t, style: .default, handler: { _ in
+            self.selectedGender = t
+            self.genderRow.value = t
+        })) }
+        ac.addAction(UIAlertAction(title: "取消", style: .cancel))
+        // ✅ 关键:指定 popover 锚点
+        presentSheet(ac, from: self.genderRow)
+    }
+
+    private enum DateKind { case birth, arrive }
+    private func chooseDate(for kind: DateKind) {
+        let initDate = (kind == .birth) ? (self.birthDate ?? Date()) : (self.arriveDate ?? Date())
+        let vc = DatePickerSheetController(initial: initDate)
+        vc.onDone = { [weak self] date in
+            guard let self = self else { return }
+            let fmt = DateFormatter(); fmt.dateFormat = "yyyy-MM-dd"
+            let text = fmt.string(from: date)
+            if kind == .birth { self.birthDate = date; self.birthRow.value = text }
+            else { self.arriveDate = date; self.arriveRow.value = text }
+        }
+        present(vc, animated: false)
+    }
+}
+
+// MARK: - Helper Views
+final class DashedSeparator: UIView {
+    private let shape = CAShapeLayer()
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        backgroundColor = .clear
+        shape.strokeColor = UIColor(hex: "#DADADA").cgColor
+        shape.lineDashPattern = [4, 4]
+        shape.lineWidth = 1
+        layer.addSublayer(shape)
+    }
+    required init?(coder: NSCoder) { fatalError() }
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        shape.frame = bounds
+        let path = UIBezierPath()
+        path.move(to: CGPoint(x: 0, y: bounds.midY))
+        path.addLine(to: CGPoint(x: bounds.width, y: bounds.midY))
+        shape.path = path.cgPath
+    }
+}
+
+final class InputRow: UIView {
+    private let titleLabel = UILabel()
+    private let textField = UITextField()
+    init(title: String, placeholder: String, showsChevron: Bool, keyboard: UIKeyboardType) {
+        super.init(frame: .zero)
+        titleLabel.text = title
+        titleLabel.font = .systemFont(ofSize: 14)
+        titleLabel.textColor = UIColor(hex: "#5B5B5B")
+
+        textField.placeholder = placeholder
+        textField.font = .systemFont(ofSize: 14)
+        textField.textAlignment = .right
+        textField.keyboardType = keyboard
+
+        addSubview(titleLabel)
+        addSubview(textField)
+        titleLabel.translatesAutoresizingMaskIntoConstraints = false
+        textField.translatesAutoresizingMaskIntoConstraints = false
+
+        NSLayoutConstraint.activate([
+            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4),
+            titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
+
+            textField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
+            textField.centerYAnchor.constraint(equalTo: centerYAnchor),
+            textField.leadingAnchor.constraint(greaterThanOrEqualTo: titleLabel.trailingAnchor, constant: 8)
+        ])
+    }
+    
+    func setEnabled(_ enabled: Bool) {
+        isUserInteractionEnabled = enabled
+        textField.textColor = enabled ? UIColor(hex: "#8B8B8B") : UIColor(hex: "#C8C8C8")
+        titleLabel.textColor = enabled ? UIColor(hex: "#5B5B5B") : UIColor(hex: "#A0A0A0")
+    }
+
+    required init?(coder: NSCoder) { fatalError() }
+    var text: String {
+        get { textField.text ?? "" }
+        set { textField.text = newValue }
+    }
+}
+
+final class SelectRow: UIControl {
+    private let titleLabel = UILabel()
+    private let valueLabel = UILabel()
+    private let chevron = UIImageView(image: UIImage(systemName: "chevron.right"))
+
+    var onTap: (() -> Void)?
+
+    // 外部控制:显示/隐藏右侧箭头;启用/禁用交互与样式
+    func setChevronHidden(_ hidden: Bool) {
+        chevron.isHidden = hidden
+    }
+    func setEnabled(_ enabled: Bool) {
+        isUserInteractionEnabled = enabled
+        valueLabel.textColor = enabled ? UIColor(hex: "#8B8B8B") : UIColor(hex: "#C8C8C8")
+        titleLabel.textColor = enabled ? UIColor(hex: "#5B5B5B") : UIColor(hex: "#A0A0A0")
+    }
+    
+    init(title: String) {
+        super.init(frame: .zero)
+        addTarget(self, action: #selector(tap), for: .touchUpInside)
+        titleLabel.text = title
+        titleLabel.font = .systemFont(ofSize: 14)
+        titleLabel.textColor = UIColor(hex: "#5B5B5B")
+
+        valueLabel.text = "请选择"
+        valueLabel.font = .systemFont(ofSize: 14)
+        valueLabel.textColor = UIColor(hex: "#8B8B8B")
+        valueLabel.textAlignment = .right
+
+        chevron.tintColor = UIColor(hex: "#C1C1C1")
+        chevron.setContentHuggingPriority(.required, for: .horizontal)
+
+        [titleLabel, valueLabel, chevron].forEach { addSubview($0); $0.translatesAutoresizingMaskIntoConstraints = false }
+
+        NSLayoutConstraint.activate([
+            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4),
+            titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
+
+            chevron.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -2),
+            chevron.centerYAnchor.constraint(equalTo: centerYAnchor),
+            chevron.widthAnchor.constraint(equalToConstant: 10),
+
+            valueLabel.trailingAnchor.constraint(equalTo: chevron.leadingAnchor, constant: -8),
+            valueLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
+            valueLabel.leadingAnchor.constraint(greaterThanOrEqualTo: titleLabel.trailingAnchor, constant: 8)
+        ])
+    }
+    required init?(coder: NSCoder) { fatalError() }
+
+    @objc private func tap() { onTap?() }
+    var value: String? { get { valueLabel.text } set { valueLabel.text = newValue } }
+}
+
+
+// MARK: - DatePickerSheetController (仿原型样式的日期弹窗)
+final class DatePickerSheetController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
+    var onDone: ((Date) -> Void)?
+
+    private let initial: Date
+    private let bg = UIControl()
+    private let sheet = UIView()
+    private let header = UIView()
+    private let titleLabel = UILabel()
+    private let closeBtn = UIButton(type: .custom)
+    private let doneBtn = UIButton(type: .custom)
+    private let picker = UIPickerView()
+    private let highlight = UIView()
+
+    private var years: [Int] = []
+    private let months = Array(1...12)
+    private var days: [Int] = []
+
+    private var selYear: Int = 0
+    private var selMonth: Int = 0
+    private var selDay: Int = 0
+
+    init(initial: Date) {
+        self.initial = initial
+        super.init(nibName: nil, bundle: nil)
+        modalPresentationStyle = .overFullScreen
+        modalTransitionStyle = .crossDissolve
+    }
+    required init?(coder: NSCoder) { fatalError() }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        view.backgroundColor = .clear
+        buildData()
+        buildUI()
+        applyInitialSelection()
+    }
+
+    private func buildData() {
+        let cal = Calendar.current
+        let nowYear = cal.component(.year, from: Date())
+        years = Array((nowYear - 50)...(nowYear + 5))
+    }
+
+    private func buildUI() {
+        // Dim background
+        bg.backgroundColor = UIColor.black.withAlphaComponent(0.45)
+        bg.addTarget(self, action: #selector(close), for: .touchUpInside)
+        view.addSubview(bg)
+        bg.translatesAutoresizingMaskIntoConstraints = false
+
+        // Sheet
+        sheet.backgroundColor = .white
+        sheet.layer.cornerRadius = 16
+        sheet.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
+        view.addSubview(sheet)
+        sheet.translatesAutoresizingMaskIntoConstraints = false
+
+        // Header
+        titleLabel.text = "选择时间"
+        titleLabel.font = .systemFont(ofSize: 16, weight: .medium)
+        titleLabel.textColor = UIColor(hex: "#2B2B2B")
+        titleLabel.textAlignment = .center
+
+        closeBtn.setImage(UIImage(named: "AddPet385"), for: .normal)
+//        closeBtn.tintColor = UIColor(hex: "#2B2B2B")
+        closeBtn.addTarget(self, action: #selector(close), for: .touchUpInside)
+
+        doneBtn.setImage(UIImage(named: "AddPet389"), for: .normal)
+//        doneBtn.tintColor = UIColor(hex: "#2B2B2B")
+        doneBtn.addTarget(self, action: #selector(doneTap), for: .touchUpInside)
+
+        header.translatesAutoresizingMaskIntoConstraints = false
+        header.addSubview(titleLabel)
+        header.addSubview(closeBtn)
+        header.addSubview(doneBtn)
+        [titleLabel, closeBtn, doneBtn].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
+
+        // Picker
+        picker.dataSource = self
+        picker.delegate = self
+        picker.translatesAutoresizingMaskIntoConstraints = false
+        picker.backgroundColor = .clear
+
+        // Highlight row (FFE059, 25% alpha)
+        highlight.backgroundColor = UIColor(hex: "#FFE059").withAlphaComponent(0.25)
+        highlight.layer.cornerRadius = 22
+        highlight.isUserInteractionEnabled = false
+        highlight.translatesAutoresizingMaskIntoConstraints = false
+
+        sheet.addSubview(header)
+        sheet.addSubview(picker)
+        sheet.addSubview(highlight)
+
+        // Layout
+        NSLayoutConstraint.activate([
+            bg.topAnchor.constraint(equalTo: view.topAnchor),
+            bg.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            bg.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+            bg.bottomAnchor.constraint(equalTo: view.bottomAnchor),
+
+            sheet.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            sheet.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+            sheet.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
+
+            header.topAnchor.constraint(equalTo: sheet.topAnchor, constant: 8),
+            header.leadingAnchor.constraint(equalTo: sheet.leadingAnchor, constant: 12),
+            header.trailingAnchor.constraint(equalTo: sheet.trailingAnchor, constant: -12),
+            header.heightAnchor.constraint(equalToConstant: 36),
+
+            closeBtn.centerYAnchor.constraint(equalTo: header.centerYAnchor),
+            closeBtn.leadingAnchor.constraint(equalTo: header.leadingAnchor),
+            closeBtn.widthAnchor.constraint(equalToConstant: 28),
+            closeBtn.heightAnchor.constraint(equalToConstant: 28),
+
+            doneBtn.centerYAnchor.constraint(equalTo: header.centerYAnchor),
+            doneBtn.trailingAnchor.constraint(equalTo: header.trailingAnchor),
+            doneBtn.widthAnchor.constraint(equalToConstant: 28),
+            doneBtn.heightAnchor.constraint(equalToConstant: 28),
+
+            titleLabel.centerXAnchor.constraint(equalTo: header.centerXAnchor),
+            titleLabel.centerYAnchor.constraint(equalTo: header.centerYAnchor),
+
+            picker.topAnchor.constraint(equalTo: header.bottomAnchor, constant: 4),
+            picker.leadingAnchor.constraint(equalTo: sheet.leadingAnchor),
+            picker.trailingAnchor.constraint(equalTo: sheet.trailingAnchor),
+            picker.bottomAnchor.constraint(equalTo: sheet.bottomAnchor),
+
+            highlight.leadingAnchor.constraint(equalTo: sheet.leadingAnchor, constant: 16),
+            highlight.trailingAnchor.constraint(equalTo: sheet.trailingAnchor, constant: -16),
+            highlight.centerYAnchor.constraint(equalTo: picker.centerYAnchor),
+            highlight.heightAnchor.constraint(equalToConstant: 44)
+        ])
+    }
+
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        // Present animation
+        sheet.transform = CGAffineTransform(translationX: 0, y: 400)
+        header.alpha = 0
+        picker.alpha = 0
+        bg.alpha = 0
+        UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseOut]) {
+            self.sheet.transform = .identity
+            self.header.alpha = 1
+            self.picker.alpha = 1
+            self.bg.alpha = 1
+        }
+    }
+
+    // MARK: - Picker data
+    func numberOfComponents(in pickerView: UIPickerView) -> Int { 3 }
+    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
+        switch component {
+        case 0: return years.count
+        case 1: return months.count
+        default: return days.count
+        }
+    }
+
+    func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
+        let w = pickerView.bounds.width
+        return component == 0 ? w * 0.4 : w * 0.3
+    }
+
+    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { 44 }
+
+    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
+        let label = (view as? UILabel) ?? UILabel()
+        label.font = .systemFont(ofSize: 18, weight: .medium)
+        label.textAlignment = component == 0 ? .center : .center
+        label.textColor = UIColor(hex: "#2B2B2B")
+        switch component {
+        case 0: label.text = "\(years[row])年"
+        case 1: label.text = String(format: "%02d月", months[row])
+        default: label.text = String(format: "%02d日", days[row])
+        }
+        // 变灰非选中项
+        let isSelected = row == pickerView.selectedRow(inComponent: component)
+        label.textColor = isSelected ? UIColor(hex: "#2B2B2B") : UIColor(hex: "#A8A8A8")
+        return label
+    }
+
+    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
+        switch component {
+        case 0: selYear = years[row]
+        case 1: selMonth = months[row]
+        case 2: selDay = days[row]
+        default: break
+        }
+        if component != 2 {
+            rebuildDays()
+            pickerView.reloadComponent(2)
+        }
+        // 让文字颜色即时更新
+        pickerView.reloadComponent(component)
+    }
+
+    private func applyInitialSelection() {
+        let cal = Calendar.current
+        selYear = cal.component(.year, from: initial)
+        selMonth = cal.component(.month, from: initial)
+        selDay = cal.component(.day, from: initial)
+        rebuildDays()
+
+        if let yi = years.firstIndex(of: selYear) {
+            picker.selectRow(yi, inComponent: 0, animated: false)
+        }
+        picker.selectRow(selMonth - 1, inComponent: 1, animated: false)
+        if let di = days.firstIndex(of: selDay) {
+            picker.selectRow(di, inComponent: 2, animated: false)
+        }
+        picker.reloadAllComponents()
+    }
+
+    private func rebuildDays() {
+        let cal = Calendar.current
+        var comps = DateComponents()
+        comps.year = selYear
+        comps.month = selMonth
+        comps.day = 1
+        let date = cal.date(from: comps) ?? Date()
+        let range = cal.range(of: .day, in: .month, for: date) ?? 1..<31
+        days = Array(range)
+        if !days.contains(selDay) { selDay = days.last ?? 1 }
+    }
+
+    @objc private func close() { dismissAnimated() }
+
+    @objc private func doneTap() {
+        var comps = DateComponents()
+        comps.year = selYear; comps.month = selMonth; comps.day = selDay
+        let cal = Calendar.current
+        let date = cal.date(from: comps) ?? Date()
+        onDone?(date)
+        dismissAnimated()
+    }
+
+    private func dismissAnimated() {
+        UIView.animate(withDuration: 0.22, animations: {
+            self.sheet.transform = CGAffineTransform(translationX: 0, y: 400)
+            self.bg.alpha = 0
+        }, completion: { _ in
+            self.dismiss(animated: false)
+        })
+    }
+}
+
+
+
+

+ 36 - 0
VenusKitto/AppDelegate.swift

@@ -0,0 +1,36 @@
+//
+//  AppDelegate.swift
+//  VenusKitto
+//
+//  Created by Neoa on 2025/8/21.
+//
+
+import UIKit
+
+@main
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+
+
+    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+        // Override point for customization after application launch.
+        return true
+    }
+
+    // MARK: UISceneSession Lifecycle
+
+    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
+        // Called when a new scene session is being created.
+        // Use this method to select a configuration to create the new scene with.
+        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
+    }
+
+    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
+        // Called when the user discards a scene session.
+        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
+        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
+    }
+
+
+}
+

+ 11 - 0
VenusKitto/Assets.xcassets/AccentColor.colorset/Contents.json

@@ -0,0 +1,11 @@
+{
+  "colors" : [
+    {
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/AddPet/AddPet383.imageset/AddPet383.png


BIN
VenusKitto/Assets.xcassets/AddPet/AddPet383.imageset/AddPet383@2x.png


BIN
VenusKitto/Assets.xcassets/AddPet/AddPet383.imageset/AddPet383@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/AddPet/AddPet383.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "AddPet383.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "AddPet383@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "AddPet383@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/AddPet/AddPet384.imageset/AddPet384.png


+ 21 - 0
VenusKitto/Assets.xcassets/AddPet/AddPet384.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "AddPet384.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/AddPet/AddPet385.imageset/AddPet385.png


+ 21 - 0
VenusKitto/Assets.xcassets/AddPet/AddPet385.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "AddPet385.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/AddPet/AddPet389.imageset/AddPet389.png


BIN
VenusKitto/Assets.xcassets/AddPet/AddPet389.imageset/AddPet389@2x.png


BIN
VenusKitto/Assets.xcassets/AddPet/AddPet389.imageset/AddPet389@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/AddPet/AddPet389.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "AddPet389.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "AddPet389@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "AddPet389@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 6 - 0
VenusKitto/Assets.xcassets/AddPet/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/AddRecord/AddRecord382.imageset/AddRecord382.png


BIN
VenusKitto/Assets.xcassets/AddRecord/AddRecord382.imageset/AddRecord382@2x.png


BIN
VenusKitto/Assets.xcassets/AddRecord/AddRecord382.imageset/AddRecord382@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/AddRecord/AddRecord382.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "AddRecord382.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "AddRecord382@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "AddRecord382@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 6 - 0
VenusKitto/Assets.xcassets/AddRecord/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 21 - 0
VenusKitto/Assets.xcassets/AddRecord/peihead.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "peihead.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/AddRecord/peihead.imageset/peihead.png


+ 38 - 0
VenusKitto/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,38 @@
+{
+  "images" : [
+    {
+      "filename" : "catlogo 3.jpg",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "filename" : "catlogo 2.jpg",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "tinted"
+        }
+      ],
+      "filename" : "catlogo 4.jpg",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/AppIcon.appiconset/catlogo 2.jpg


BIN
VenusKitto/Assets.xcassets/AppIcon.appiconset/catlogo 3.jpg


BIN
VenusKitto/Assets.xcassets/AppIcon.appiconset/catlogo 4.jpg


BIN
VenusKitto/Assets.xcassets/Bookkeep/Bookkeep395.imageset/Bookkeep395.png


BIN
VenusKitto/Assets.xcassets/Bookkeep/Bookkeep395.imageset/Bookkeep395@2x.png


BIN
VenusKitto/Assets.xcassets/Bookkeep/Bookkeep395.imageset/Bookkeep395@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/Bookkeep/Bookkeep395.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Bookkeep395.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Bookkeep395@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Bookkeep395@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 6 - 0
VenusKitto/Assets.xcassets/Bookkeep/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 6 - 0
VenusKitto/Assets.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 21 - 0
VenusKitto/Assets.xcassets/catlogos.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "catlogos.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/catlogos.imageset/catlogos.jpg


+ 6 - 0
VenusKitto/Assets.xcassets/home/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 23 - 0
VenusKitto/Assets.xcassets/home/Home289.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home289.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home289@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home289@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home289.imageset/Home289.png


BIN
VenusKitto/Assets.xcassets/home/Home289.imageset/Home289@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home289.imageset/Home289@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home290.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home290.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home290@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home290@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home290.imageset/Home290.png


BIN
VenusKitto/Assets.xcassets/home/Home290.imageset/Home290@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home290.imageset/Home290@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home291.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home291.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home291@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home291@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home291.imageset/Home291.png


BIN
VenusKitto/Assets.xcassets/home/Home291.imageset/Home291@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home291.imageset/Home291@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home292.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home292.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home292@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home292@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home292.imageset/Home292.png


BIN
VenusKitto/Assets.xcassets/home/Home292.imageset/Home292@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home292.imageset/Home292@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home293.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home293.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home293@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home293@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home293.imageset/Home293.png


BIN
VenusKitto/Assets.xcassets/home/Home293.imageset/Home293@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home293.imageset/Home293@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home357.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home357.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home357@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home357@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home357.imageset/Home357.png


BIN
VenusKitto/Assets.xcassets/home/Home357.imageset/Home357@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home357.imageset/Home357@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home358.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home358.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home358@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home358@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home358.imageset/Home358.png


BIN
VenusKitto/Assets.xcassets/home/Home358.imageset/Home358@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home358.imageset/Home358@3x.png


+ 21 - 0
VenusKitto/Assets.xcassets/home/Home359.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Home359.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home359.imageset/Home359.png


+ 21 - 0
VenusKitto/Assets.xcassets/home/Home360.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Home360.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home360.imageset/Home360.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home361.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home361.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home361@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home361@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home361.imageset/Home361.png


BIN
VenusKitto/Assets.xcassets/home/Home361.imageset/Home361@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home361.imageset/Home361@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home371.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home371.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home371@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home371@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home371.imageset/Home371.png


BIN
VenusKitto/Assets.xcassets/home/Home371.imageset/Home371@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home371.imageset/Home371@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home372.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home372.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home372@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home372@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home372.imageset/Home372.png


BIN
VenusKitto/Assets.xcassets/home/Home372.imageset/Home372@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home372.imageset/Home372@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home373.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home373.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home373@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home373@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home373.imageset/Home373.png


BIN
VenusKitto/Assets.xcassets/home/Home373.imageset/Home373@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home373.imageset/Home373@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home374.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home374.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home374@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home374@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home374.imageset/Home374.png


BIN
VenusKitto/Assets.xcassets/home/Home374.imageset/Home374@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home374.imageset/Home374@3x.png


+ 23 - 0
VenusKitto/Assets.xcassets/home/Home375.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "Home375.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Home375@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home375@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home375.imageset/Home375.png


BIN
VenusKitto/Assets.xcassets/home/Home375.imageset/Home375@2x.png


BIN
VenusKitto/Assets.xcassets/home/Home375.imageset/Home375@3x.png


+ 21 - 0
VenusKitto/Assets.xcassets/home/Home377.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Home377@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
VenusKitto/Assets.xcassets/home/Home377.imageset/Home377@3x.png


Some files were not shown because too many files changed in this diff