Pārlūkot izejas kodu

init: 项目基础文件

陈文艺 4 mēneši atpakaļ
vecāks
revīzija
4814d98495
37 mainītis faili ar 1825 papildinājumiem un 0 dzēšanām
  1. 27 0
      .gitignore
  2. 686 0
      Lanu.xcodeproj/project.pbxproj
  3. 78 0
      Lanu.xcodeproj/xcshareddata/xcschemes/Lanu.xcscheme
  4. 33 0
      Lanu/AppDelegate.swift
  5. 11 0
      Lanu/Assets.xcassets/AccentColor.colorset/Contents.json
  6. 35 0
      Lanu/Assets.xcassets/AppIcon.appiconset/Contents.json
  7. 6 0
      Lanu/Assets.xcassets/Contents.json
  8. 25 0
      Lanu/Base.lproj/LaunchScreen.storyboard
  9. 17 0
      Lanu/Common/Config/LNAppConfig.swift
  10. 98 0
      Lanu/Common/Storage/LNUserDefaults.swift
  11. 12 0
      Lanu/Common/Storage/LNUserDefaultsKey.swift
  12. 8 0
      Lanu/Common/Theme/UIColor+Theme.swift
  13. 8 0
      Lanu/Common/Theme/UIFont+Theme.swift
  14. 19 0
      Lanu/Common/Utils/String+Extension.swift
  15. 70 0
      Lanu/Common/Utils/UIColor+Extension.swift
  16. 54 0
      Lanu/Common/Views/Base/LNBaseViewController.swift
  17. 43 0
      Lanu/Common/Views/Base/LNNavigationController.swift
  18. 23 0
      Lanu/Info.plist
  19. 7 0
      Lanu/Localizable.xcstrings
  20. 32 0
      Lanu/Manager/Account/LNAccountManager.swift
  21. 45 0
      Lanu/Manager/LNDelayTask.swift
  22. 65 0
      Lanu/Manager/LNEventDeliver.swift
  23. 230 0
      Lanu/Manager/Network/LNHTTPManager.swift
  24. 17 0
      Lanu/Manager/Network/LNHttpResponse.swift
  25. 15 0
      Lanu/Manager/Network/LNNetworkConfig.swift
  26. 8 0
      Lanu/Manager/Order/LNOrderManager.swift
  27. 8 0
      Lanu/Manager/Profile/LNProfileManager.swift
  28. 8 0
      Lanu/Manager/Purchase/LNPurchaseManager.swift
  29. 55 0
      Lanu/SceneDelegate.swift
  30. 17 0
      Lanu/Views/Main/LNMainViewController.swift
  31. 9 0
      Lanu/en.lproj/InfoPlist.strings
  32. 9 0
      Lanu/id.lproj/InfoPlist.strings
  33. 1 0
      Lanu/id.lproj/LaunchScreen.strings
  34. 9 0
      Lanu/zh-Hans.lproj/InfoPlist.strings
  35. 1 0
      Lanu/zh-Hans.lproj/LaunchScreen.strings
  36. 14 0
      Podfile
  37. 22 0
      Podfile.lock

+ 27 - 0
.gitignore

@@ -0,0 +1,27 @@
+## User settings
+xcuserdata/
+
+## Obj-C/Swift specific
+*.hmap
+
+## App packaging
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+# CocoaPods
+Pods/
+
+# Add this line if you want to avoid checking in source code from the Xcode workspace
+*.xcworkspace
+
+# fastlane
+# It is recommended to not store the screenshots in the git repo.
+# Instead, use fastlane to re-generate the screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots/**/*.png
+fastlane/test_output

+ 686 - 0
Lanu.xcodeproj/project.pbxproj

@@ -0,0 +1,686 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 77;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		0DE4E86CB596C7E4A75DCD81 /* Pods_Lanu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABE0E79254D94F91C773E929 /* Pods_Lanu.framework */; };
+		FB15AF1E2EBC9057009EE6F7 /* LNUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB15AF1D2EBC9057009EE6F7 /* LNUserDefaults.swift */; };
+		FB8677E02EBC98E000DDCE30 /* LNUserDefaultsKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB8677DF2EBC98E000DDCE30 /* LNUserDefaultsKey.swift */; };
+		FBFE13C42EBC39B000DCE6E9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE13C32EBC39B000DCE6E9 /* AppDelegate.swift */; };
+		FBFE13C62EBC39B000DCE6E9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE13C52EBC39B000DCE6E9 /* SceneDelegate.swift */; };
+		FBFE13CD2EBC39B100DCE6E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FBFE13CC2EBC39B100DCE6E9 /* Assets.xcassets */; };
+		FBFE13D02EBC39B100DCE6E9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FBFE13CE2EBC39B100DCE6E9 /* LaunchScreen.storyboard */; };
+		FBFE13E12EBC3B6200DCE6E9 /* LNNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE13E02EBC3B6200DCE6E9 /* LNNavigationController.swift */; };
+		FBFE13E32EBC3B6C00DCE6E9 /* LNBaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE13E22EBC3B6C00DCE6E9 /* LNBaseViewController.swift */; };
+		FBFE13E62EBC3E8600DCE6E9 /* LNMainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE13E52EBC3E8600DCE6E9 /* LNMainViewController.swift */; };
+		FBFE141E2EBC855000DCE6E9 /* AutoCodable in Frameworks */ = {isa = PBXBuildFile; productRef = FBFE141D2EBC855000DCE6E9 /* AutoCodable */; };
+		FBFE14202EBC860700DCE6E9 /* LNAccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE141F2EBC860700DCE6E9 /* LNAccountManager.swift */; };
+		FBFE14222EBC861300DCE6E9 /* LNProfileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14212EBC861300DCE6E9 /* LNProfileManager.swift */; };
+		FBFE14242EBC861C00DCE6E9 /* LNPurchaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14232EBC861C00DCE6E9 /* LNPurchaseManager.swift */; };
+		FBFE14262EBC862500DCE6E9 /* LNOrderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14252EBC862500DCE6E9 /* LNOrderManager.swift */; };
+		FBFE14392EBC86C400DCE6E9 /* LNEventDeliver.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14382EBC86C400DCE6E9 /* LNEventDeliver.swift */; };
+		FBFE143B2EBC86DB00DCE6E9 /* LNDelayTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE143A2EBC86DB00DCE6E9 /* LNDelayTask.swift */; };
+		FBFE143E2EBC89E300DCE6E9 /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE143D2EBC89E300DCE6E9 /* UIColor+Extension.swift */; };
+		FBFE14402EBC8A1200DCE6E9 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE143F2EBC8A1200DCE6E9 /* String+Extension.swift */; };
+		FBFE14432EBC8AB800DCE6E9 /* LNHTTPManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14422EBC8AB800DCE6E9 /* LNHTTPManager.swift */; };
+		FBFE14462EBC8AFD00DCE6E9 /* LNAppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14452EBC8AFD00DCE6E9 /* LNAppConfig.swift */; };
+		FBFE14482EBC8B3D00DCE6E9 /* LNHttpResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14472EBC8B3D00DCE6E9 /* LNHttpResponse.swift */; };
+		FBFE144A2EBC8B9700DCE6E9 /* LNNetworkConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14492EBC8B9700DCE6E9 /* LNNetworkConfig.swift */; };
+		FBFE144F2EBC8CCC00DCE6E9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FBFE144E2EBC8CCC00DCE6E9 /* InfoPlist.strings */; };
+		FBFE14512EBC8CED00DCE6E9 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = FBFE14502EBC8CED00DCE6E9 /* Localizable.xcstrings */; };
+		FBFE14562EBC8DBB00DCE6E9 /* UIFont+Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14552EBC8DBB00DCE6E9 /* UIFont+Theme.swift */; };
+		FBFE14582EBC8DC200DCE6E9 /* UIColor+Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBFE14572EBC8DC200DCE6E9 /* UIColor+Theme.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		006A9E8625309678F4BEF8AB /* Pods-Lanu.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Lanu.release.xcconfig"; path = "Target Support Files/Pods-Lanu/Pods-Lanu.release.xcconfig"; sourceTree = "<group>"; };
+		036D0D2B175E726D1FD387A9 /* Pods-Lanu.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Lanu.debug.xcconfig"; path = "Target Support Files/Pods-Lanu/Pods-Lanu.debug.xcconfig"; sourceTree = "<group>"; };
+		ABE0E79254D94F91C773E929 /* Pods_Lanu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Lanu.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		FB15AF1D2EBC9057009EE6F7 /* LNUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNUserDefaults.swift; sourceTree = "<group>"; };
+		FB8677DF2EBC98E000DDCE30 /* LNUserDefaultsKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNUserDefaultsKey.swift; sourceTree = "<group>"; };
+		FBFE13C02EBC39B000DCE6E9 /* Lanu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Lanu.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		FBFE13C32EBC39B000DCE6E9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+		FBFE13C52EBC39B000DCE6E9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
+		FBFE13CC2EBC39B100DCE6E9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		FBFE13CF2EBC39B100DCE6E9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		FBFE13D12EBC39B100DCE6E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		FBFE13E02EBC3B6200DCE6E9 /* LNNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNNavigationController.swift; sourceTree = "<group>"; };
+		FBFE13E22EBC3B6C00DCE6E9 /* LNBaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNBaseViewController.swift; sourceTree = "<group>"; };
+		FBFE13E52EBC3E8600DCE6E9 /* LNMainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNMainViewController.swift; sourceTree = "<group>"; };
+		FBFE141F2EBC860700DCE6E9 /* LNAccountManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNAccountManager.swift; sourceTree = "<group>"; };
+		FBFE14212EBC861300DCE6E9 /* LNProfileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNProfileManager.swift; sourceTree = "<group>"; };
+		FBFE14232EBC861C00DCE6E9 /* LNPurchaseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNPurchaseManager.swift; sourceTree = "<group>"; };
+		FBFE14252EBC862500DCE6E9 /* LNOrderManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNOrderManager.swift; sourceTree = "<group>"; };
+		FBFE14382EBC86C400DCE6E9 /* LNEventDeliver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNEventDeliver.swift; sourceTree = "<group>"; };
+		FBFE143A2EBC86DB00DCE6E9 /* LNDelayTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNDelayTask.swift; sourceTree = "<group>"; };
+		FBFE143D2EBC89E300DCE6E9 /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = "<group>"; };
+		FBFE143F2EBC8A1200DCE6E9 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
+		FBFE14422EBC8AB800DCE6E9 /* LNHTTPManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNHTTPManager.swift; sourceTree = "<group>"; };
+		FBFE14452EBC8AFD00DCE6E9 /* LNAppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNAppConfig.swift; sourceTree = "<group>"; };
+		FBFE14472EBC8B3D00DCE6E9 /* LNHttpResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNHttpResponse.swift; sourceTree = "<group>"; };
+		FBFE14492EBC8B9700DCE6E9 /* LNNetworkConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LNNetworkConfig.swift; sourceTree = "<group>"; };
+		FBFE144B2EBC8CCC00DCE6E9 /* InfoPlist.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = InfoPlist.strings; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		FBFE144C2EBC8CCC00DCE6E9 /* InfoPlist.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = InfoPlist.strings; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
+		FBFE144D2EBC8CCC00DCE6E9 /* InfoPlist.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = InfoPlist.strings; path = id.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		FBFE14502EBC8CED00DCE6E9 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
+		FBFE14522EBC8D1800DCE6E9 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
+		FBFE14532EBC8D1F00DCE6E9 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/LaunchScreen.strings"; sourceTree = "<group>"; };
+		FBFE14552EBC8DBB00DCE6E9 /* UIFont+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Theme.swift"; sourceTree = "<group>"; };
+		FBFE14572EBC8DC200DCE6E9 /* UIColor+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Theme.swift"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		FBFE13BD2EBC39B000DCE6E9 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FBFE141E2EBC855000DCE6E9 /* AutoCodable in Frameworks */,
+				0DE4E86CB596C7E4A75DCD81 /* Pods_Lanu.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		3BCF7245871F5939F104E2E4 /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				036D0D2B175E726D1FD387A9 /* Pods-Lanu.debug.xcconfig */,
+				006A9E8625309678F4BEF8AB /* Pods-Lanu.release.xcconfig */,
+			);
+			path = Pods;
+			sourceTree = "<group>";
+		};
+		B29B70049832FAE5EB51A5C4 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				ABE0E79254D94F91C773E929 /* Pods_Lanu.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		FB8677DE2EBC98D100DDCE30 /* Storage */ = {
+			isa = PBXGroup;
+			children = (
+				FB15AF1D2EBC9057009EE6F7 /* LNUserDefaults.swift */,
+				FB8677DF2EBC98E000DDCE30 /* LNUserDefaultsKey.swift */,
+			);
+			path = Storage;
+			sourceTree = "<group>";
+		};
+		FBFE13B72EBC39B000DCE6E9 = {
+			isa = PBXGroup;
+			children = (
+				FBFE13D82EBC39D200DCE6E9 /* Lanu */,
+				FBFE13C12EBC39B000DCE6E9 /* Products */,
+				3BCF7245871F5939F104E2E4 /* Pods */,
+				B29B70049832FAE5EB51A5C4 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		FBFE13C12EBC39B000DCE6E9 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE13C02EBC39B000DCE6E9 /* Lanu.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		FBFE13D82EBC39D200DCE6E9 /* Lanu */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE13DB2EBC3AF500DCE6E9 /* Views */,
+				FBFE13DC2EBC3AFE00DCE6E9 /* Manager */,
+				FBFE13DD2EBC3B0500DCE6E9 /* Common */,
+				FBFE13C32EBC39B000DCE6E9 /* AppDelegate.swift */,
+				FBFE13CC2EBC39B100DCE6E9 /* Assets.xcassets */,
+				FBFE13D12EBC39B100DCE6E9 /* Info.plist */,
+				FBFE14502EBC8CED00DCE6E9 /* Localizable.xcstrings */,
+				FBFE144E2EBC8CCC00DCE6E9 /* InfoPlist.strings */,
+				FBFE13CE2EBC39B100DCE6E9 /* LaunchScreen.storyboard */,
+				FBFE13C52EBC39B000DCE6E9 /* SceneDelegate.swift */,
+			);
+			path = Lanu;
+			sourceTree = "<group>";
+		};
+		FBFE13DB2EBC3AF500DCE6E9 /* Views */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE13E42EBC3E7E00DCE6E9 /* Main */,
+			);
+			path = Views;
+			sourceTree = "<group>";
+		};
+		FBFE13DC2EBC3AFE00DCE6E9 /* Manager */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE14412EBC8AB600DCE6E9 /* Network */,
+				FBFE13F92EBC528400DCE6E9 /* Order */,
+				FBFE13F82EBC526000DCE6E9 /* Purchase */,
+				FBFE13F72EBC525B00DCE6E9 /* Profile */,
+				FBFE13F62EBC525400DCE6E9 /* Account */,
+				FBFE14382EBC86C400DCE6E9 /* LNEventDeliver.swift */,
+				FBFE143A2EBC86DB00DCE6E9 /* LNDelayTask.swift */,
+			);
+			path = Manager;
+			sourceTree = "<group>";
+		};
+		FBFE13DD2EBC3B0500DCE6E9 /* Common */ = {
+			isa = PBXGroup;
+			children = (
+				FB8677DE2EBC98D100DDCE30 /* Storage */,
+				FBFE14542EBC8DAD00DCE6E9 /* Theme */,
+				FBFE14442EBC8AF500DCE6E9 /* Config */,
+				FBFE143C2EBC89E100DCE6E9 /* Utils */,
+				FBFE13DE2EBC3B3C00DCE6E9 /* Views */,
+			);
+			path = Common;
+			sourceTree = "<group>";
+		};
+		FBFE13DE2EBC3B3C00DCE6E9 /* Views */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE13DF2EBC3B5000DCE6E9 /* Base */,
+			);
+			path = Views;
+			sourceTree = "<group>";
+		};
+		FBFE13DF2EBC3B5000DCE6E9 /* Base */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE13E02EBC3B6200DCE6E9 /* LNNavigationController.swift */,
+				FBFE13E22EBC3B6C00DCE6E9 /* LNBaseViewController.swift */,
+			);
+			path = Base;
+			sourceTree = "<group>";
+		};
+		FBFE13E42EBC3E7E00DCE6E9 /* Main */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE13E52EBC3E8600DCE6E9 /* LNMainViewController.swift */,
+			);
+			path = Main;
+			sourceTree = "<group>";
+		};
+		FBFE13F62EBC525400DCE6E9 /* Account */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE141F2EBC860700DCE6E9 /* LNAccountManager.swift */,
+			);
+			path = Account;
+			sourceTree = "<group>";
+		};
+		FBFE13F72EBC525B00DCE6E9 /* Profile */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE14212EBC861300DCE6E9 /* LNProfileManager.swift */,
+			);
+			path = Profile;
+			sourceTree = "<group>";
+		};
+		FBFE13F82EBC526000DCE6E9 /* Purchase */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE14232EBC861C00DCE6E9 /* LNPurchaseManager.swift */,
+			);
+			path = Purchase;
+			sourceTree = "<group>";
+		};
+		FBFE13F92EBC528400DCE6E9 /* Order */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE14252EBC862500DCE6E9 /* LNOrderManager.swift */,
+			);
+			path = Order;
+			sourceTree = "<group>";
+		};
+		FBFE143C2EBC89E100DCE6E9 /* Utils */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE143D2EBC89E300DCE6E9 /* UIColor+Extension.swift */,
+				FBFE143F2EBC8A1200DCE6E9 /* String+Extension.swift */,
+			);
+			path = Utils;
+			sourceTree = "<group>";
+		};
+		FBFE14412EBC8AB600DCE6E9 /* Network */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE14422EBC8AB800DCE6E9 /* LNHTTPManager.swift */,
+				FBFE14472EBC8B3D00DCE6E9 /* LNHttpResponse.swift */,
+				FBFE14492EBC8B9700DCE6E9 /* LNNetworkConfig.swift */,
+			);
+			path = Network;
+			sourceTree = "<group>";
+		};
+		FBFE14442EBC8AF500DCE6E9 /* Config */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE14452EBC8AFD00DCE6E9 /* LNAppConfig.swift */,
+			);
+			path = Config;
+			sourceTree = "<group>";
+		};
+		FBFE14542EBC8DAD00DCE6E9 /* Theme */ = {
+			isa = PBXGroup;
+			children = (
+				FBFE14552EBC8DBB00DCE6E9 /* UIFont+Theme.swift */,
+				FBFE14572EBC8DC200DCE6E9 /* UIColor+Theme.swift */,
+			);
+			path = Theme;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		FBFE13BF2EBC39B000DCE6E9 /* Lanu */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = FBFE13D32EBC39B100DCE6E9 /* Build configuration list for PBXNativeTarget "Lanu" */;
+			buildPhases = (
+				AC205607300F610A882B2531 /* [CP] Check Pods Manifest.lock */,
+				FBFE13BC2EBC39B000DCE6E9 /* Sources */,
+				FBFE13BD2EBC39B000DCE6E9 /* Frameworks */,
+				FBFE13BE2EBC39B000DCE6E9 /* Resources */,
+				D90817FF000AD0800F0D2736 /* [CP] Embed Pods Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Lanu;
+			productName = Lanu;
+			productReference = FBFE13C02EBC39B000DCE6E9 /* Lanu.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		FBFE13B82EBC39B000DCE6E9 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				BuildIndependentTargetsInParallel = 1;
+				LastSwiftUpdateCheck = 2600;
+				LastUpgradeCheck = 2600;
+				TargetAttributes = {
+					FBFE13BF2EBC39B000DCE6E9 = {
+						CreatedOnToolsVersion = 26.0.1;
+					};
+				};
+			};
+			buildConfigurationList = FBFE13BB2EBC39B000DCE6E9 /* Build configuration list for PBXProject "Lanu" */;
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+				id,
+				"zh-Hans",
+			);
+			mainGroup = FBFE13B72EBC39B000DCE6E9;
+			minimizedProjectReferenceProxies = 1;
+			packageReferences = (
+				FB15AF1F2EBC9313009EE6F7 /* XCRemoteSwiftPackageReference "AutoCodable" */,
+			);
+			preferredProjectObjectVersion = 77;
+			productRefGroup = FBFE13C12EBC39B000DCE6E9 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				FBFE13BF2EBC39B000DCE6E9 /* Lanu */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		FBFE13BE2EBC39B000DCE6E9 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FBFE13D02EBC39B100DCE6E9 /* LaunchScreen.storyboard in Resources */,
+				FBFE144F2EBC8CCC00DCE6E9 /* InfoPlist.strings in Resources */,
+				FBFE14512EBC8CED00DCE6E9 /* Localizable.xcstrings in Resources */,
+				FBFE13CD2EBC39B100DCE6E9 /* Assets.xcassets in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		AC205607300F610A882B2531 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-Lanu-checkManifestLockResult.txt",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			showEnvVarsInLog = 0;
+		};
+		D90817FF000AD0800F0D2736 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Lanu/Pods-Lanu-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Lanu/Pods-Lanu-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Lanu/Pods-Lanu-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		FBFE13BC2EBC39B000DCE6E9 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				FBFE143B2EBC86DB00DCE6E9 /* LNDelayTask.swift in Sources */,
+				FBFE14262EBC862500DCE6E9 /* LNOrderManager.swift in Sources */,
+				FBFE14242EBC861C00DCE6E9 /* LNPurchaseManager.swift in Sources */,
+				FBFE14432EBC8AB800DCE6E9 /* LNHTTPManager.swift in Sources */,
+				FBFE14202EBC860700DCE6E9 /* LNAccountManager.swift in Sources */,
+				FBFE14582EBC8DC200DCE6E9 /* UIColor+Theme.swift in Sources */,
+				FBFE14482EBC8B3D00DCE6E9 /* LNHttpResponse.swift in Sources */,
+				FBFE14392EBC86C400DCE6E9 /* LNEventDeliver.swift in Sources */,
+				FBFE13E12EBC3B6200DCE6E9 /* LNNavigationController.swift in Sources */,
+				FBFE13E32EBC3B6C00DCE6E9 /* LNBaseViewController.swift in Sources */,
+				FBFE13C42EBC39B000DCE6E9 /* AppDelegate.swift in Sources */,
+				FBFE13C62EBC39B000DCE6E9 /* SceneDelegate.swift in Sources */,
+				FB15AF1E2EBC9057009EE6F7 /* LNUserDefaults.swift in Sources */,
+				FBFE143E2EBC89E300DCE6E9 /* UIColor+Extension.swift in Sources */,
+				FBFE13E62EBC3E8600DCE6E9 /* LNMainViewController.swift in Sources */,
+				FBFE14462EBC8AFD00DCE6E9 /* LNAppConfig.swift in Sources */,
+				FBFE14562EBC8DBB00DCE6E9 /* UIFont+Theme.swift in Sources */,
+				FB8677E02EBC98E000DDCE30 /* LNUserDefaultsKey.swift in Sources */,
+				FBFE14222EBC861300DCE6E9 /* LNProfileManager.swift in Sources */,
+				FBFE144A2EBC8B9700DCE6E9 /* LNNetworkConfig.swift in Sources */,
+				FBFE14402EBC8A1200DCE6E9 /* String+Extension.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		FBFE13CE2EBC39B100DCE6E9 /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				FBFE13CF2EBC39B100DCE6E9 /* Base */,
+				FBFE14522EBC8D1800DCE6E9 /* id */,
+				FBFE14532EBC8D1F00DCE6E9 /* zh-Hans */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+		FBFE144E2EBC8CCC00DCE6E9 /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				FBFE144B2EBC8CCC00DCE6E9 /* InfoPlist.strings */,
+				FBFE144C2EBC8CCC00DCE6E9 /* InfoPlist.strings */,
+				FBFE144D2EBC8CCC00DCE6E9 /* InfoPlist.strings */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		FBFE13D42EBC39B100DCE6E9 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 036D0D2B175E726D1FD387A9 /* Pods-Lanu.debug.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				DEVELOPMENT_TEAM = JLGY6N3NUP;
+				ENABLE_USER_SCRIPT_SANDBOXING = NO;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = Lanu/Info.plist;
+				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.lanu.app;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				STRING_CATALOG_GENERATE_SYMBOLS = YES;
+				SWIFT_APPROACHABLE_CONCURRENCY = YES;
+				SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		FBFE13D52EBC39B100DCE6E9 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 006A9E8625309678F4BEF8AB /* Pods-Lanu.release.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				DEVELOPMENT_TEAM = JLGY6N3NUP;
+				ENABLE_USER_SCRIPT_SANDBOXING = NO;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = Lanu/Info.plist;
+				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+				INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+				IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.lanu.app;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				STRING_CATALOG_GENERATE_SYMBOLS = YES;
+				SWIFT_APPROACHABLE_CONCURRENCY = YES;
+				SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+		FBFE13D62EBC39B100DCE6E9 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = 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 = 26.0;
+				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_EMIT_LOC_STRINGS = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+			};
+			name = Debug;
+		};
+		FBFE13D72EBC39B100DCE6E9 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = 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 = 26.0;
+				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				SDKROOT = iphoneos;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		FBFE13BB2EBC39B000DCE6E9 /* Build configuration list for PBXProject "Lanu" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				FBFE13D62EBC39B100DCE6E9 /* Debug */,
+				FBFE13D72EBC39B100DCE6E9 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		FBFE13D32EBC39B100DCE6E9 /* Build configuration list for PBXNativeTarget "Lanu" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				FBFE13D42EBC39B100DCE6E9 /* Debug */,
+				FBFE13D52EBC39B100DCE6E9 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+		FB15AF1F2EBC9313009EE6F7 /* XCRemoteSwiftPackageReference "AutoCodable" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "http://8.134.139.102:10880/mail_onee/AutoCodable";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 1.0.0;
+			};
+		};
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+		FBFE141D2EBC855000DCE6E9 /* AutoCodable */ = {
+			isa = XCSwiftPackageProductDependency;
+			productName = AutoCodable;
+		};
+/* End XCSwiftPackageProductDependency section */
+	};
+	rootObject = FBFE13B82EBC39B000DCE6E9 /* Project object */;
+}

+ 78 - 0
Lanu.xcodeproj/xcshareddata/xcschemes/Lanu.xcscheme

@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "2600"
+   version = "1.7">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES"
+      buildArchitectures = "Automatic">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "FBFE13BF2EBC39B000DCE6E9"
+               BuildableName = "Lanu.app"
+               BlueprintName = "Lanu"
+               ReferencedContainer = "container:Lanu.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      shouldAutocreateTestPlan = "YES">
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "FBFE13BF2EBC39B000DCE6E9"
+            BuildableName = "Lanu.app"
+            BlueprintName = "Lanu"
+            ReferencedContainer = "container:Lanu.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "FBFE13BF2EBC39B000DCE6E9"
+            BuildableName = "Lanu.app"
+            BlueprintName = "Lanu"
+            ReferencedContainer = "container:Lanu.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 33 - 0
Lanu/AppDelegate.swift

@@ -0,0 +1,33 @@
+//
+//  AppDelegate.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import UIKit
+
+@main
+class AppDelegate: UIResponder, UIApplicationDelegate {
+    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+        // Override point for customization after application launch.
+        
+        LNEventDeliver.notifyAppLaunchFinished()
+        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
Lanu/Assets.xcassets/AccentColor.colorset/Contents.json

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

+ 35 - 0
Lanu/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,35 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "tinted"
+        }
+      ],
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

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

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

+ 25 - 0
Lanu/Base.lproj/LaunchScreen.storyboard

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>

+ 17 - 0
Lanu/Common/Config/LNAppConfig.swift

@@ -0,0 +1,17 @@
+//
+//  LNAppConfig.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+enum LNAppEnvType: Codable {
+    case test
+    case official
+}
+
+class LNAppConfig {
+    static var curEnv: LNAppEnvType = .official
+}

+ 98 - 0
Lanu/Common/Storage/LNUserDefaults.swift

@@ -0,0 +1,98 @@
+//
+//  LNUserDefaults.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+var LNUserDefaults: LNUserDefaultsManager {
+    LNUserDefaultsManager.shared
+}
+
+class LNUserDefaultsManager {
+    static let shared = LNUserDefaultsManager()
+    private init() {}
+    
+    // 内存缓存容器
+    private var cache: [String: Any] = [:]
+    // 存储容器(支持 App Group)
+    private let userDefaults: UserDefaults = {
+        // 如需共享数据,可替换为 App Group 的 suiteName
+        // return UserDefaults(suiteName: "your.app.group") ?? .standard
+        return .standard
+    }()
+    
+    
+    subscript<T: Codable>(_ key: LNUserDefaultsKey, _ defaultValue: T) -> T {
+        value(forKey: key) ?? defaultValue
+    }
+    
+    subscript<T: Codable>(_ key: LNUserDefaultsKey) -> T? {
+        get {
+            value(forKey: key) ?? nil
+        }
+        set {
+            save(newValue, forKey: key)
+        }
+    }
+    
+    /// 存储数据(自动编码)
+    private func save<T: Codable>(_ value: T, forKey key: LNUserDefaultsKey) {
+        do {
+            let data = try JSONEncoder().encode(value)
+            userDefaults.set(data, forKey: key.rawValue)
+            // 更新缓存
+            cache[key.rawValue] = value
+        } catch {
+#if DEBUG
+            print("存储失败(key: \(key)):\(error)")
+#endif
+        }
+    }
+    
+    /// 读取数据(自动推断类型,无需显式传递 Type.self)
+    private func value<T: Codable>(forKey key: LNUserDefaultsKey) -> T? {
+        // 优先从缓存读取
+        if let cached = cache[key.rawValue] as? T {
+            return cached
+        }
+        
+        // 从 UserDefaults 读取并解码
+        guard let data = userDefaults.data(forKey: key.rawValue) else {
+            cache.removeValue(forKey: key.rawValue) // 清除无效缓存
+            return nil
+        }
+        
+        do {
+            let decoded = try JSONDecoder().decode(T.self, from: data)
+            // 缓存解码后的数据
+            cache[key.rawValue] = decoded
+            return decoded
+        } catch {
+#if DEBUG
+            print("读取失败(key: \(key.rawValue)):\(error)")
+#endif
+            cache.removeValue(forKey: key.rawValue)
+            return nil
+        }
+    }
+    
+    // 辅助方法:删除数据
+    func remove(forKey key: LNUserDefaultsKey) {
+        userDefaults.removeObject(forKey: key.rawValue)
+        cache.removeValue(forKey: key.rawValue)
+    }
+    
+    // 辅助方法:清除所有数据(包括缓存)
+    func clearAll() {
+        userDefaults.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
+        cache.removeAll()
+    }
+    
+    // 辅助方法:仅清除内存缓存
+    func clearCache() {
+        cache.removeAll()
+    }
+}

+ 12 - 0
Lanu/Common/Storage/LNUserDefaultsKey.swift

@@ -0,0 +1,12 @@
+//
+//  LNUserDefaultsKey.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+enum LNUserDefaultsKey: String {
+    case uid
+}

+ 8 - 0
Lanu/Common/Theme/UIColor+Theme.swift

@@ -0,0 +1,8 @@
+//
+//  UIColor+Theme.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation

+ 8 - 0
Lanu/Common/Theme/UIFont+Theme.swift

@@ -0,0 +1,8 @@
+//
+//  UIFont+Theme.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation

+ 19 - 0
Lanu/Common/Utils/String+Extension.swift

@@ -0,0 +1,19 @@
+//
+//  String+Extension.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+
+extension String {
+    init(key: String) {
+        self = NSLocalizedString(key, comment: "")
+    }
+    
+    init(key: String, _ with: any CVarArg...) {
+        self = String(format: NSLocalizedString(key, comment: ""), with)
+    }
+}

+ 70 - 0
Lanu/Common/Utils/UIColor+Extension.swift

@@ -0,0 +1,70 @@
+//
+//  UIColor+Extension.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+import UIKit
+
+extension UIColor {
+    /// 从十六进制字符串创建UIColor,转换失败时返回透明色
+    /// - Parameter hexString: 十六进制颜色字符串,格式可以是 "#RGB", "#RGBA", "#RRGGBB", "#RRGGBBAA"
+    convenience init(hex: String) {
+        // 移除字符串中的 # 符号和空白字符
+        let cleanedString = hex.trimmingCharacters(in: .whitespacesAndNewlines).replacingOccurrences(of: "#", with: "")
+        
+        var rgbValue: UInt64 = 0
+        // 扫描字符串并转换为UInt64
+        let success = Scanner(string: cleanedString).scanHexInt64(&rgbValue)
+        
+        let red: CGFloat
+        let green: CGFloat
+        let blue: CGFloat
+        let alpha: CGFloat
+        
+        if success {
+            switch cleanedString.count {
+            case 3: // RGB (12-bit)
+                red = CGFloat((rgbValue & 0xF00) >> 8) / 15.0
+                green = CGFloat((rgbValue & 0x0F0) >> 4) / 15.0
+                blue = CGFloat(rgbValue & 0x00F) / 15.0
+                alpha = 1.0
+                
+            case 4: // RGBA (16-bit)
+                red = CGFloat((rgbValue & 0xF000) >> 12) / 15.0
+                green = CGFloat((rgbValue & 0x0F00) >> 8) / 15.0
+                blue = CGFloat((rgbValue & 0x00F0) >> 4) / 15.0
+                alpha = CGFloat(rgbValue & 0x000F) / 15.0
+                
+            case 6: // RGB (24-bit)
+                red = CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0
+                green = CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0
+                blue = CGFloat(rgbValue & 0x0000FF) / 255.0
+                alpha = 1.0
+                
+            case 8: // RGBA (32-bit)
+                red = CGFloat((rgbValue & 0xFF000000) >> 24) / 255.0
+                green = CGFloat((rgbValue & 0x00FF0000) >> 16) / 255.0
+                blue = CGFloat((rgbValue & 0x0000FF00) >> 8) / 255.0
+                alpha = CGFloat(rgbValue & 0x000000FF) / 255.0
+                
+            default:
+                // 不符合任何支持的格式,使用透明色
+                red = 0
+                green = 0
+                blue = 0
+                alpha = 0
+            }
+        } else {
+            // 扫描失败,使用透明色
+            red = 0
+            green = 0
+            blue = 0
+            alpha = 0
+        }
+        
+        self.init(red: red, green: green, blue: blue, alpha: alpha)
+    }
+}

+ 54 - 0
Lanu/Common/Views/Base/LNBaseViewController.swift

@@ -0,0 +1,54 @@
+//
+//  LNBaseViewController.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+import UIKit
+
+
+class LNBaseViewController: UIViewController {
+    var showNavigationBar = true
+    var enableDragBack = true
+    var navigationBarColor: UIColor = .white
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        view.backgroundColor = .white
+        edgesForExtendedLayout = []
+//        hidesBottomBarWhenPushed = true
+        
+        let button = UIButton(type: .system)
+        button.addAction(UIAction(handler: { [weak self] _ in
+            guard let self else { return }
+            navigationController?.popViewController(animated: true)
+        }), for: .touchUpInside)
+        let buttonImage: UIImage? = .init(systemName: "chevron.backward")?.withRenderingMode(.alwaysTemplate)
+        button.contentHorizontalAlignment = .center
+        button.setImage(buttonImage, for: .normal)
+        button.tintColor = .black
+        navigationItem.leftBarButtonItem = UIBarButtonItem(customView: button)
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        
+        navigationController?.setNavigationBarHidden(!showNavigationBar, animated: animated)
+        
+        if !showNavigationBar,
+           let navBar = navigationController?.navigationBar {
+            // 1. 配置外观(iOS 15+ 必须用 UINavigationBarAppearance)
+            let appearance = UINavigationBarAppearance()
+            appearance.backgroundColor = navigationBarColor // 导航栏背景色
+            appearance.shadowColor = .clear // 去除底部阴影线
+            
+            // 2. 应用外观设置(iOS 15+ 需要设置 scrollEdgeAppearance 和 standardAppearance)
+            navBar.scrollEdgeAppearance = appearance // 滚动到顶部时的外观(如列表顶部)
+            navBar.standardAppearance = appearance   // 常规状态的外观
+            navBar.compactAppearance = appearance
+        }
+    }
+}

+ 43 - 0
Lanu/Common/Views/Base/LNNavigationController.swift

@@ -0,0 +1,43 @@
+//
+//  LNNavigationController.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+import UIKit
+
+class LNNavigationController: UINavigationController {
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        interactivePopGestureRecognizer?.delegate = self
+        navigationBar.backgroundColor = .white
+        
+        configureNavigationBarAppearance()
+    }
+    
+    // 配置导航栏及返回按钮的全局样式
+    private func configureNavigationBarAppearance() {
+        let navBarAppearance = UINavigationBarAppearance()
+        
+//        navBarAppearance.backgroundColor = .backgroundSecondary // 导航栏背景色
+        navBarAppearance.shadowColor = .clear // 去除底部阴影线
+        
+        UINavigationBar.appearance().standardAppearance = navBarAppearance
+        UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance
+    }
+}
+
+extension LNNavigationController: UIGestureRecognizerDelegate {
+    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
+        guard viewControllers.count > 1 else { return false }
+        guard let viewController = viewControllers.last as? LNBaseViewController else { return true }
+        return viewController.enableDragBack
+    }
+    
+    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
+        true
+    }
+}

+ 23 - 0
Lanu/Info.plist

@@ -0,0 +1,23 @@
+<?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>UIApplicationSceneManifest</key>
+	<dict>
+		<key>UIApplicationSupportsMultipleScenes</key>
+		<false/>
+		<key>UISceneConfigurations</key>
+		<dict>
+			<key>UIWindowSceneSessionRoleApplication</key>
+			<array>
+				<dict>
+					<key>UISceneConfigurationName</key>
+					<string>Default Configuration</string>
+					<key>UISceneDelegateClassName</key>
+					<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
+				</dict>
+			</array>
+		</dict>
+	</dict>
+</dict>
+</plist>

+ 7 - 0
Lanu/Localizable.xcstrings

@@ -0,0 +1,7 @@
+{
+  "sourceLanguage" : "en",
+  "strings" : {
+
+  },
+  "version" : "1.1"
+}

+ 32 - 0
Lanu/Manager/Account/LNAccountManager.swift

@@ -0,0 +1,32 @@
+//
+//  LNAccountManager.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+
+
+protocol LNUserMainEvent {
+    func onUserLogin()
+    func onUserLogout()
+}
+extension LNUserMainEvent {
+    func onUserLogin() {}
+    func onUserLogout() {}
+}
+
+class LNAccountManager {
+}
+
+extension LNAccountManager {
+    static func notifyUserLogin() {
+        LNEventDeliver.notifyEvent { ($0 as? LNUserMainEvent)?.onUserLogin() }
+    }
+
+    static func notifyUserLogout() {
+        LNEventDeliver.notifyEvent { ($0 as? LNUserMainEvent)?.onUserLogout() }
+    }
+}

+ 45 - 0
Lanu/Manager/LNDelayTask.swift

@@ -0,0 +1,45 @@
+//
+//  LNDelayTask.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+class MODelayTask {
+    // 保存任务实例,用于取消
+    private static var workItems = NSMapTable<NSString, DispatchWorkItem>.init(
+        keyOptions: .strongMemory,
+        valueOptions: .weakMemory
+    )
+    
+    /// 执行延时任务(可取消)
+    /// - Parameters:
+    ///   - delay: 延时秒数
+    ///   - queue: 执行队列(默认主线程)
+    ///   - task: 延时后执行的任务
+    @discardableResult
+    static func perform(delay: TimeInterval, queue: DispatchQueue = .main, task: @escaping () -> Void) -> String {
+        // 创建任务
+        let workItem = DispatchWorkItem(block: task)
+        let uuid = UUID().uuidString
+        workItems.setObject(workItem, forKey: uuid as NSString)
+        
+        // 延时执行
+        queue.asyncAfter(deadline: .now() + delay, execute: workItem)
+        
+        return uuid
+    }
+    
+    /// 取消延时任务
+    static func cancel(key: String?) {
+        guard let key else { return }
+        guard let task = workItems.object(forKey: key as NSString) else {
+            return
+        }
+        workItems.removeObject(forKey: key as NSString)
+        
+        task.cancel()
+    }
+}

+ 65 - 0
Lanu/Manager/LNEventDeliver.swift

@@ -0,0 +1,65 @@
+//
+//  LNEventDeliver.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+protocol LNAppMainEvent {
+    func onAppLaunchFinished()
+}
+extension LNAppMainEvent {
+    func onAppLaunchFinished() {}
+}
+
+class LNEventDeliver {
+    private static let lock = NSLock()
+    private static let observers = NSHashTable<AnyObject>.weakObjects()
+    
+    static func addObserver(_ observer: AnyObject) {
+        lock.lock()
+        guard !observers.contains(observer) else {
+            lock.unlock()
+            return
+        }
+        observers.add(observer)
+        lock.unlock()
+    }
+    
+    static func removeObserver(_ observer: AnyObject) {
+        lock.lock()
+        guard observers.contains(observer) else {
+            lock.unlock()
+            return
+        }
+        observers.remove(observer)
+        lock.unlock()
+    }
+    
+    static func notifyEvent(_ event: (AnyObject) -> Void) {
+        lock.lock()
+        let allObservers = observers.allObjects
+        lock.unlock()
+        
+        allObservers.forEach { event($0) }
+    }
+    
+    static func notifyEvent(_ queue: DispatchQueue, _ event: @escaping (AnyObject) -> Void, ) {
+        lock.lock()
+        let allObservers = observers.allObjects
+        lock.unlock()
+        
+        queue.async {
+            allObservers.forEach { event($0) }
+        }
+    }
+}
+
+// 主要事件的通知方法
+extension LNEventDeliver {
+    static func notifyAppLaunchFinished() {
+        notifyEvent { ($0 as? LNAppMainEvent)?.onAppLaunchFinished() }
+    }
+}

+ 230 - 0
Lanu/Manager/Network/LNHTTPManager.swift

@@ -0,0 +1,230 @@
+//
+//  LNHTTPManager.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+/// HTTP请求方法枚举
+enum HTTPMethod: String {
+    case get = "GET"
+    case post = "POST"
+    case put = "PUT"
+    case delete = "DELETE"
+}
+
+/// HTTP请求错误枚举
+enum HTTPError: Error, LocalizedError {
+    case invalidURL
+    case invalidResponse
+    case networkError(Error)
+    case parsingError(Error)
+    case statusCode(Int)
+    case serverError(String)
+    
+    var errorDescription: String? {
+        switch self {
+        case .invalidURL:
+            return "无效的URL"
+        case .invalidResponse:
+            return "无效的响应"
+        case .networkError(let error):
+            return "网络错误: \(error.localizedDescription)"
+        case .parsingError(let error):
+            return "解析错误: \(error.localizedDescription)"
+        case .statusCode(let code):
+            return "请求失败,状态码: \(code)"
+        case .serverError(let error):
+            return error
+        }
+    }
+}
+
+/// HTTP请求管理器
+class LNHTTPManager {
+    static let shared = LNHTTPManager()
+    private let session: URLSession
+    private var curConfig = LNNetworkConfig()
+    
+    private init() {
+        let configuration = URLSessionConfiguration.default
+        configuration.timeoutIntervalForRequest = 30
+        configuration.timeoutIntervalForResource = 60
+        session = URLSession(configuration: configuration)
+    }
+    
+    /// 通用HTTP请求方法
+    /// - Parameters:
+    ///   - urlString: 请求URL字符串
+    ///   - method: HTTP方法
+    ///   - parameters: 请求参数
+    ///   - headers: 请求头
+    ///   - completion: 完成回调
+    func request<T: Decodable>(
+        path: String,
+        method: HTTPMethod = .get,
+        parameters: [String: Any]? = nil,
+        headers: [String: String]? = nil,
+        completion: @escaping (Result<T?, HTTPError>) -> Void
+    ) {
+        let commonHeader: [String: String] = [
+            "Content-Type": " application/json"
+        ]
+        
+        let mergedHeader = commonHeader.merging(headers ?? [:]) { $1 }
+        
+        // 检查URL是否有效
+        guard let url = buildURL(from: path, method: method, parameters: parameters) else {
+            completion(.failure(.invalidURL))
+            return
+        }
+        
+        // 创建请求
+        var request = URLRequest(url: url)
+        request.httpMethod = method.rawValue
+        
+        // 设置请求头
+        mergedHeader.forEach { key, value in
+            request.addValue(value, forHTTPHeaderField: key)
+        }
+        
+        // 设置请求体(POST, PUT等方法)
+        if method != .get, let parameters = parameters {
+            request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)
+        }
+        
+        // 执行请求
+        let task = session.dataTask(with: request) { [weak self] data, response, error in
+            guard let self else { return }
+            
+            // 处理网络错误
+            if let error = error {
+#if DEBUG
+                print("receive \(request.url?.absoluteString ?? "") error: \(error.localizedDescription)")
+#endif
+                completion(.failure(.networkError(error)))
+                return
+            }
+            
+            // 检查响应是否有效
+            guard let httpResponse = response as? HTTPURLResponse else {
+#if DEBUG
+                print("receive \(request.url?.absoluteString ?? "") response error")
+#endif
+                completion(.failure(.invalidResponse))
+                return
+            }
+            
+#if DEBUG
+            print("receive \(request.url?.absoluteString ?? "") code:\(httpResponse.statusCode)")
+            if let data {
+                print("data \(String(data: data, encoding: .utf8) ?? "")")
+            }
+#endif
+            
+            // 检查状态码
+            guard 200...299 ~= httpResponse.statusCode else {
+                completion(.failure(.statusCode(httpResponse.statusCode)))
+                return
+            }
+            
+            // 处理响应数据
+            guard let data = data else {
+                // 如果没有数据但状态码正常,尝试返回空对象
+                if let emptyData = "{}".data(using: .utf8),
+                   let result = try? JSONDecoder().decode(T.self, from: emptyData) {
+                    completion(.success(result))
+                } else {
+                    completion(.failure(.invalidResponse))
+                }
+                return
+            }
+            
+            // 解析JSON数据
+            self.parseJSON(data: data, completion: completion)
+        }
+        
+#if DEBUG
+        print(
+            "send \(request.httpMethod ?? "") - \(request.url?.absoluteString ?? "")"
+        )
+        if let body = request.httpBody {
+            print("\(String(data: body, encoding: .utf8) ?? "")")
+        }
+#endif
+        task.resume()
+    }
+    
+    /// 构建请求URL(处理GET参数)
+    private func buildURL(from path: String, method: HTTPMethod, parameters: [String: Any]?) -> URL? {
+        guard var urlComponents = URLComponents(string: curConfig.host + (path.starts(with: "/") ? path : "/\(path)")) else {
+            return nil
+        }
+        
+        // GET方法的参数拼接到URL上
+        if method == .get, let parameters = parameters {
+            urlComponents.queryItems = parameters.map { key, value in
+                URLQueryItem(name: key, value: "\(value)")
+            }
+        }
+        
+        return urlComponents.url
+    }
+    
+    /// 解析JSON数据
+    private func parseJSON<T: Decodable>(data: Data, completion: @escaping (Result<T?, HTTPError>) -> Void) {
+        do {
+            let decoder = JSONDecoder()
+            decoder.keyDecodingStrategy = .convertFromSnakeCase // 处理蛇形命名
+            let result = try decoder.decode(LNHttpResponse<T>.self, from: data)
+            if result.code != 0 {
+                completion(.failure(.serverError(result.msg)))
+            } else {
+                completion(.success(result.data))
+            }
+        } catch {
+            completion(.failure(.parsingError(error)))
+        }
+    }
+}
+
+// MARK: - 便捷请求方法扩展
+extension LNHTTPManager {
+    /// 发送GET请求
+    func get<T: Decodable>(
+        path: String,
+        params: [String: Any]? = nil,
+        completion: @escaping (Result<T?, HTTPError>) -> Void
+    ) {
+        request(path: path, method: .get, parameters: params, completion: completion)
+    }
+    
+    /// 发送POST请求
+    func post<T: Decodable>(
+        path: String,
+        params: [String: Any]? = nil,
+        completion: @escaping (Result<T?, HTTPError>) -> Void
+    ) {
+        request(path: path, method: .post, parameters: params, completion: completion)
+    }
+    
+    /// 发送PUT请求
+    func put<T: Decodable>(
+        path: String,
+        params: [String: Any]? = nil,
+        completion: @escaping (Result<T?, HTTPError>) -> Void
+    ) {
+        request(path: path, method: .put, parameters: params, completion: completion)
+    }
+    
+    /// 发送DELETE请求
+    func delete<T: Decodable>(
+        path: String,
+        params: [String: Any]? = nil,
+        completion: @escaping (Result<T?, HTTPError>) -> Void
+    ) {
+        request(path: path, method: .delete, parameters: params, completion: completion)
+    }
+}

+ 17 - 0
Lanu/Manager/Network/LNHttpResponse.swift

@@ -0,0 +1,17 @@
+//
+//  LNHttpResponse.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+import AutoCodable
+
+@AutoCodable
+class LNHttpResponse<T: Decodable>: Decodable {
+    var code: Int = 0
+    var timestamp: Int = 0
+    var msg: String = ""
+    var data: T? = nil
+}

+ 15 - 0
Lanu/Manager/Network/LNNetworkConfig.swift

@@ -0,0 +1,15 @@
+//
+//  LNNetworkConfig.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+
+
+class LNNetworkConfig {
+    var host: String {
+        ""
+    }
+}

+ 8 - 0
Lanu/Manager/Order/LNOrderManager.swift

@@ -0,0 +1,8 @@
+//
+//  LNOrderManager.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation

+ 8 - 0
Lanu/Manager/Profile/LNProfileManager.swift

@@ -0,0 +1,8 @@
+//
+//  LNProfileManager.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation

+ 8 - 0
Lanu/Manager/Purchase/LNPurchaseManager.swift

@@ -0,0 +1,8 @@
+//
+//  LNPurchaseManager.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation

+ 55 - 0
Lanu/SceneDelegate.swift

@@ -0,0 +1,55 @@
+//
+//  SceneDelegate.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import UIKit
+
+class SceneDelegate: UIResponder, UIWindowSceneDelegate {
+
+    var window: UIWindow?
+
+
+    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
+        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
+        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
+        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
+        guard let sceneWindow = (scene as? UIWindowScene) else { return }
+        
+        window = UIWindow(windowScene: sceneWindow)
+        window?.backgroundColor = .white
+        window?.rootViewController = LNNavigationController(rootViewController: LNMainViewController())
+        window?.makeKeyAndVisible()
+    }
+
+    func sceneDidDisconnect(_ scene: UIScene) {
+        // Called as the scene is being released by the system.
+        // This occurs shortly after the scene enters the background, or when its session is discarded.
+        // Release any resources associated with this scene that can be re-created the next time the scene connects.
+        // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
+    }
+
+    func sceneDidBecomeActive(_ scene: UIScene) {
+        // Called when the scene has moved from an inactive state to an active state.
+        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
+    }
+
+    func sceneWillResignActive(_ scene: UIScene) {
+        // Called when the scene will move from an active state to an inactive state.
+        // This may occur due to temporary interruptions (ex. an incoming phone call).
+    }
+
+    func sceneWillEnterForeground(_ scene: UIScene) {
+        // Called as the scene transitions from the background to the foreground.
+        // Use this method to undo the changes made on entering the background.
+    }
+
+    func sceneDidEnterBackground(_ scene: UIScene) {
+        // Called as the scene transitions from the foreground to the background.
+        // Use this method to save data, release shared resources, and store enough scene-specific state information
+        // to restore the scene back to its current state.
+    }
+}
+

+ 17 - 0
Lanu/Views/Main/LNMainViewController.swift

@@ -0,0 +1,17 @@
+//
+//  LNMainViewController.swift
+//  Lanu
+//
+//  Created by OneeChan on 2025/11/6.
+//
+
+import Foundation
+import UIKit
+
+class LNMainViewController: LNBaseViewController {
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        showNavigationBar = false
+    }
+}

+ 9 - 0
Lanu/en.lproj/InfoPlist.strings

@@ -0,0 +1,9 @@
+/* 
+  InfoPlist.strings
+  Lanu
+
+  Created by OneeChan on 2025/11/6.
+  
+*/
+
+"NSLocationWhenInUseUsageDescription" = "Your consent is required to open the location";

+ 9 - 0
Lanu/id.lproj/InfoPlist.strings

@@ -0,0 +1,9 @@
+/* 
+  InfoPlist.strings
+  Lanu
+
+  Created by OneeChan on 2025/11/6.
+  
+*/
+
+"NSLocationWhenInUseUsageDescription" = "Your consent is required to open the location";

+ 1 - 0
Lanu/id.lproj/LaunchScreen.strings

@@ -0,0 +1 @@
+

+ 9 - 0
Lanu/zh-Hans.lproj/InfoPlist.strings

@@ -0,0 +1,9 @@
+/* 
+  InfoPlist.strings
+  Lanu
+
+  Created by OneeChan on 2025/11/6.
+  
+*/
+
+"NSLocationWhenInUseUsageDescription" = "需要您的同意才能打开位置";

+ 1 - 0
Lanu/zh-Hans.lproj/LaunchScreen.strings

@@ -0,0 +1 @@
+

+ 14 - 0
Podfile

@@ -0,0 +1,14 @@
+# Uncomment the next line to define a global platform for your project
+platform :ios, '15.0'
+
+source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'
+
+target 'Lanu' do
+  # Comment the next line if you don't want to use dynamic frameworks
+  use_frameworks!
+
+  # Pods for Lanu
+  pod 'SnapKit'
+  pod 'SDWebImage'
+
+end

+ 22 - 0
Podfile.lock

@@ -0,0 +1,22 @@
+PODS:
+  - SDWebImage (5.21.3):
+    - SDWebImage/Core (= 5.21.3)
+  - SDWebImage/Core (5.21.3)
+  - SnapKit (5.7.1)
+
+DEPENDENCIES:
+  - SDWebImage
+  - SnapKit
+
+SPEC REPOS:
+  https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git:
+    - SDWebImage
+    - SnapKit
+
+SPEC CHECKSUMS:
+  SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a
+  SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
+
+PODFILE CHECKSUM: f2235161cb0c966d45a0f0fe75b341959605a293
+
+COCOAPODS: 1.16.2