Commit e9fc7fcd authored by yqz's avatar yqz

新建项目

parent 00b0300b
Pipeline #1815 failed with stages
# Created by https://www.gitignore.io/api/xcode
### Xcode ###
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint
### Xcode Patch ###
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddat
!*/xcuserdata/admin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlista/
!*.xcworkspace/contents.xcworkspacedata
/*.gcno
# End of https://www.gitignore.io/api/xcode
# Created by https://www.gitignore.io/api/cocoapods
### CocoaPods ###
## CocoaPods GitIgnore Template
# CocoaPods - Only use to conserve bandwidth / Save time on Pushing
# - Also handy if you have a large number of dependant pods
# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
Pods/
Podfile.lock
.DS_Store
# End of https://www.gitignore.io/api/cocoapods
\ No newline at end of file
# 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'
#source 'https://github.com/CocoaPods/Specs.git' # 备用源
target 'SpeakEasyLearnEnglish' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
pod 'Moya', '~> 15.0.0'
pod 'lottie-ios', '~> 4.5.2'
pod 'SnapKit', '~> 5.7.1'
end
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
BF2C014808039221F7439EEB /* Pods_SpeakEasyLearnEnglish.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39D9E543F43FE88873E16904 /* Pods_SpeakEasyLearnEnglish.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
04611C792E155D34009BF401 /* SpeakEasyLearnEnglish.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpeakEasyLearnEnglish.app; sourceTree = BUILT_PRODUCTS_DIR; };
39D9E543F43FE88873E16904 /* Pods_SpeakEasyLearnEnglish.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SpeakEasyLearnEnglish.framework; sourceTree = BUILT_PRODUCTS_DIR; };
AC765BC67D3A4B592761CFF5 /* Pods-SpeakEasyLearnEnglish.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SpeakEasyLearnEnglish.debug.xcconfig"; path = "Target Support Files/Pods-SpeakEasyLearnEnglish/Pods-SpeakEasyLearnEnglish.debug.xcconfig"; sourceTree = "<group>"; };
B1B287B7285F909339F45303 /* Pods-SpeakEasyLearnEnglish.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SpeakEasyLearnEnglish.release.xcconfig"; path = "Target Support Files/Pods-SpeakEasyLearnEnglish/Pods-SpeakEasyLearnEnglish.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
04611C8B2E155D36009BF401 /* Exceptions for "SpeakEasyLearnEnglish" folder in "SpeakEasyLearnEnglish" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = 04611C782E155D34009BF401 /* SpeakEasyLearnEnglish */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
04611C7B2E155D34009BF401 /* SpeakEasyLearnEnglish */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
04611C8B2E155D36009BF401 /* Exceptions for "SpeakEasyLearnEnglish" folder in "SpeakEasyLearnEnglish" target */,
);
path = SpeakEasyLearnEnglish;
sourceTree = "<group>";
};
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */
04611C762E155D34009BF401 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BF2C014808039221F7439EEB /* Pods_SpeakEasyLearnEnglish.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
04611C702E155D34009BF401 = {
isa = PBXGroup;
children = (
04611C7B2E155D34009BF401 /* SpeakEasyLearnEnglish */,
04611C7A2E155D34009BF401 /* Products */,
EB6D0FA4DB77875BE575ECE3 /* Pods */,
4D673D9C4A584D4DFCDE973A /* Frameworks */,
);
sourceTree = "<group>";
};
04611C7A2E155D34009BF401 /* Products */ = {
isa = PBXGroup;
children = (
04611C792E155D34009BF401 /* SpeakEasyLearnEnglish.app */,
);
name = Products;
sourceTree = "<group>";
};
4D673D9C4A584D4DFCDE973A /* Frameworks */ = {
isa = PBXGroup;
children = (
39D9E543F43FE88873E16904 /* Pods_SpeakEasyLearnEnglish.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
EB6D0FA4DB77875BE575ECE3 /* Pods */ = {
isa = PBXGroup;
children = (
AC765BC67D3A4B592761CFF5 /* Pods-SpeakEasyLearnEnglish.debug.xcconfig */,
B1B287B7285F909339F45303 /* Pods-SpeakEasyLearnEnglish.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
04611C782E155D34009BF401 /* SpeakEasyLearnEnglish */ = {
isa = PBXNativeTarget;
buildConfigurationList = 04611C8C2E155D36009BF401 /* Build configuration list for PBXNativeTarget "SpeakEasyLearnEnglish" */;
buildPhases = (
9156B80EE6AFE522138EE4C5 /* [CP] Check Pods Manifest.lock */,
04611C752E155D34009BF401 /* Sources */,
04611C762E155D34009BF401 /* Frameworks */,
04611C772E155D34009BF401 /* Resources */,
99FA87F8A4A0195330B133CC /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
04611C7B2E155D34009BF401 /* SpeakEasyLearnEnglish */,
);
name = SpeakEasyLearnEnglish;
productName = SpeakEasyLearnEnglish;
productReference = 04611C792E155D34009BF401 /* SpeakEasyLearnEnglish.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
04611C712E155D34009BF401 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
CLASSPREFIX = SpeakEle;
LastSwiftUpdateCheck = 1630;
LastUpgradeCheck = 1630;
TargetAttributes = {
04611C782E155D34009BF401 = {
CreatedOnToolsVersion = 16.3;
};
};
};
buildConfigurationList = 04611C742E155D34009BF401 /* Build configuration list for PBXProject "SpeakEasyLearnEnglish" */;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 04611C702E155D34009BF401;
minimizedProjectReferenceProxies = 1;
preferredProjectObjectVersion = 77;
productRefGroup = 04611C7A2E155D34009BF401 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
04611C782E155D34009BF401 /* SpeakEasyLearnEnglish */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
04611C772E155D34009BF401 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
9156B80EE6AFE522138EE4C5 /* [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-SpeakEasyLearnEnglish-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;
};
99FA87F8A4A0195330B133CC /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SpeakEasyLearnEnglish/Pods-SpeakEasyLearnEnglish-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-SpeakEasyLearnEnglish/Pods-SpeakEasyLearnEnglish-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SpeakEasyLearnEnglish/Pods-SpeakEasyLearnEnglish-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
04611C752E155D34009BF401 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
04611C8D2E155D36009BF401 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = AC765BC67D3A4B592761CFF5 /* Pods-SpeakEasyLearnEnglish.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 = 6K23946NQ5;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = SpeakEasyLearnEnglish/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "SpeakEasy: Learn English";
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.Widget.SpeakEasyLearnEnglish;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
};
04611C8E2E155D36009BF401 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B1B287B7285F909339F45303 /* Pods-SpeakEasyLearnEnglish.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 = 6K23946NQ5;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = SpeakEasyLearnEnglish/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "SpeakEasy: Learn English";
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.Widget.SpeakEasyLearnEnglish;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
name = Release;
};
04611C8F2E155D36009BF401 /* 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;
DEVELOPMENT_TEAM = 6K23946NQ5;
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.4;
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;
};
04611C902E155D36009BF401 /* 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";
DEVELOPMENT_TEAM = 6K23946NQ5;
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.4;
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 */
04611C742E155D34009BF401 /* Build configuration list for PBXProject "SpeakEasyLearnEnglish" */ = {
isa = XCConfigurationList;
buildConfigurations = (
04611C8F2E155D36009BF401 /* Debug */,
04611C902E155D36009BF401 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
04611C8C2E155D36009BF401 /* Build configuration list for PBXNativeTarget "SpeakEasyLearnEnglish" */ = {
isa = XCConfigurationList;
buildConfigurations = (
04611C8D2E155D36009BF401 /* Debug */,
04611C8E2E155D36009BF401 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 04611C712E155D34009BF401 /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1630"
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 = "04611C782E155D34009BF401"
BuildableName = "SpeakEasyLearnEnglish.app"
BlueprintName = "SpeakEasyLearnEnglish"
ReferencedContainer = "container:SpeakEasyLearnEnglish.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 = "04611C782E155D34009BF401"
BuildableName = "SpeakEasyLearnEnglish.app"
BlueprintName = "SpeakEasyLearnEnglish"
ReferencedContainer = "container:SpeakEasyLearnEnglish.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "OS_ACTIVITY_MODE"
value = "disable"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "04611C782E155D34009BF401"
BuildableName = "SpeakEasyLearnEnglish.app"
BlueprintName = "SpeakEasyLearnEnglish"
ReferencedContainer = "container:SpeakEasyLearnEnglish.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:SpeakEasyLearnEnglish.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"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
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "icon_Settings_weixuan.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_Settings_weixuan@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_Settings_weixuan@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "icon_Settings_yixuan.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_Settings_yixuan@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_Settings_yixuan@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "icon_home_weixuan.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_home_weixuan@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_home_weixuan@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "icon_home_yixuan.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_home_yixuan@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_home_yixuan@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
<?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>
//
// AppDelegate.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/2.
//
import UIKit
import SnapKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
_ = SpeakVideoPlayer.share
// 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.
}
}
//
// SceneDelegate.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/2.
//
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
internal var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = SpeakEleBaseNavigationCtr(rootViewController: SpeakEleTabbarViewCtr())
window?.makeKeyAndVisible()
UIScrollView.appearance().contentInsetAdjustmentBehavior = .never
UITableView.appearance().contentInsetAdjustmentBehavior = .never
UICollectionView.appearance().contentInsetAdjustmentBehavior = .never
}
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.
}
}
//
// SpeakEleBaseNavigationCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
class SpeakEleBaseNavigationCtr: UINavigationController, UIGestureRecognizerDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.isNavigationBarHidden = true
self.delegate = self;
self.interactivePopGestureRecognizer?.delegate = self
}
override var childForStatusBarStyle: UIViewController? {
return self.topViewController
}
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
super.pushViewController(viewController, animated: animated)
if viewControllers.count == 1 {
viewController.hidesBottomBarWhenPushed = false
}
}
override func popViewController(animated: Bool) -> UIViewController? {
let ctr = super.popViewController(animated: animated)
return ctr
}
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool{
if children.count == 1 {
return false
}else {
return true
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
//
// SpeakEleBaseViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
class SpeakEleBaseViewCtr: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setup()
}
func setup() -> Void {
}
deinit {
Print("\(type(of: self)) deinit")
}
}
//
// SpeakEleTabbarViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
class SpeakEleTabbarViewCtr: UIViewController {
public var selectIndex = 0 {
didSet {
for (i,but) in tabBarItems.enumerated() {
but.isSelected = (i == selectIndex)
}
UIView.animate(withDuration: 0.35, delay: 0, options: .curveEaseOut) {
self.scroll.contentOffset = CGPointMake(CGFloat(self.selectIndex) * self.scroll.width, 0)
}
}
}
private var tabBarItems:[TabbarButton] = [] {
didSet {
stack.arrangedSubviews.forEach({stack.removeArrangedSubview($0)})
tabBarItems.forEach({stack.addArrangedSubview($0)})
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
AddchildVC()
setup()
selectIndex = 0
}
private func AddchildVC() -> Void {
let home = TabbarButton(title: "Home", normalImage: "icon_home_weixuan", selectImage: "icon_home_yixuan")
let homevc = SpeakEleHomeViewCtr()
self.addChild(homevc)
contentStack.addArrangedSubview(homevc.view)
let set = TabbarButton(title: "Setting", normalImage: "icon_Settings_weixuan", selectImage: "icon_Settings_yixuan")
let setvc = SpeakEleSetViewCtr()
self.addChild(setvc)
contentStack.addArrangedSubview(setvc.view)
tabBarItems = [
home,
set
]
for (i,btn) in tabBarItems.enumerated() {
btn.tag = i
btn.addTarget(self, action: #selector(SpeakTouches(_:)), for: .touchUpInside)
}
}
@objc private func SpeakTouches(_ sender:UIButton) -> Void {
if sender.tag == selectIndex {
return
}
selectIndex = sender.tag
}
private func setup() -> Void {
scroll.snp.makeConstraints { make in
make.left.right.bottom.top.equalToSuperview()
}
contentStack.snp.makeConstraints { make in
make.left.top.equalToSuperview()
make.width.equalToSuperview().multipliedBy(self.tabBarItems.count)
make.height.equalToSuperview()
}
stack.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.bottom.equalToSuperview().inset(Dev.safeAreaInsets.bottom)
make.height.equalTo(Dev.tabHeight)
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.view.layoutIfNeeded()
view.bringSubviewToFront(stack)
scroll.contentSize = CGSizeMake(CGFloat(self.tabBarItems.count) * scroll.width, 0)
}
private lazy var stack: UIStackView = {
let stack = UIStackView()
stack.spacing = 0
stack.distribution = .fillEqually
stack.alignment = .fill
stack.axis = .horizontal
view.addSubview(stack)
return stack
}()
private lazy var scroll: UIScrollView = {
let scroll = UIScrollView()
scroll.isPagingEnabled = true
scroll.isScrollEnabled = false
scroll.showsVerticalScrollIndicator = false
scroll.showsHorizontalScrollIndicator = false
view.addSubview(scroll)
return scroll
}()
private lazy var contentStack: UIStackView = {
let stack = UIStackView()
stack.axis = .horizontal
stack.spacing = 0
stack.distribution = .fillEqually
stack.alignment = .fill
scroll.addSubview(stack)
return stack
}()
}
class TabbarButton: UIButton {
convenience init(title:String?, normalImage:String, selectImage:String) {
self.init(type: .custom)
var configs = UIButton.Configuration.filled()
configs.title = title
configs.baseBackgroundColor = .clear
configs.baseForegroundColor = .gray
configs.imagePlacement = .top
configs.imagePadding = 2
configs.titleAlignment = .center
configs.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer({ containar in
var att = containar
att.font = UIFont.systemFont(ofSize: 12, weight: .regular)
return att
})
self.configuration = configs
self.configurationUpdateHandler = { button in
var updateConfigs = button.configuration
if button.isSelected {
updateConfigs?.baseForegroundColor = .init(with: "#17CB81")
updateConfigs?.image = UIImage(named: selectImage)?.withRenderingMode(.alwaysOriginal)
}else{
updateConfigs?.baseForegroundColor = .gray
updateConfigs?.image = UIImage(named: normalImage)?.withRenderingMode(.alwaysOriginal)
}
button.configuration = updateConfigs
}
}
}
//
// Common.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
struct Dev {
static let screenW = UIScreen.main.bounds.size.width
static let screenH = UIScreen.main.bounds.size.height
static let navHeight:CGFloat = 44
static let tabHeight = 49
static let safeAreaInsets:UIEdgeInsets = window.safeAreaInsets
}
let window:UIWindow = {
if #available(iOS 13, *) {
return UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.first?.windows.first ?? UIWindow()
} else {
return UIApplication.shared.keyWindow ?? UIWindow()
}
}()
public func Print(_ items: Any...,
file: String = #file,
line: Int = #line,
function: String = #function) {
#if DEBUG
let fileURL = URL(fileURLWithPath: file).lastPathComponent
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm:ss.SSS"
let timestamp = dateFormatter.string(from: Date())
let output = items.map { "\($0)" }.joined(separator: " ")
print("[\(timestamp)] \(fileURL):\(line) \(function) \n\t\(output)\n")
#else
#endif
}
//
// SpeakEleConfigs.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
#if DEBUG
let isDebug = true
#else
let isDebug = false
#endif
//
// Array+Extension.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
extension Array {
subscript(safe index: Int) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
//
// String+Extension.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
extension String {
func attributed() -> AttributedStringBuilder {
return AttributedStringBuilder(self)
}
// 支持多个字符串组合的富文本
func combined(with other: NSAttributedString) -> NSAttributedString {
let result = NSMutableAttributedString(string: self)
result.append(other)
return result
}
}
class AttributedStringBuilder {
private var attributes: [NSAttributedString.Key: Any] = [:]
private var string: String = ""
init(_ string: String) {
self.string = string
}
/// 设置字体
@discardableResult
func font(_ font: UIFont) -> Self {
attributes[.font] = font
return self
}
/// 设置文本颜色
@discardableResult
func color(_ color: UIColor) -> Self {
attributes[.foregroundColor] = color
return self
}
/// 设置背景颜色
@discardableResult
func backgroundColor(_ color: UIColor) -> Self {
attributes[.backgroundColor] = color
return self
}
/// 设置下划线
@discardableResult
func underline(_ style: NSUnderlineStyle = .single) -> Self {
attributes[.underlineStyle] = style.rawValue
return self
}
/// 设置删除线
@discardableResult
func strikethrough(_ style: NSUnderlineStyle = .single) -> Self {
attributes[.strikethroughStyle] = style.rawValue
return self
}
/// 设置段落样式
@discardableResult
func paragraphStyle(_ alignment: NSTextAlignment = .left, lineSpacing: CGFloat = 0) -> Self {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = alignment
paragraphStyle.lineSpacing = lineSpacing
attributes[.paragraphStyle] = paragraphStyle
return self
}
/// 设置字符间距
@discardableResult
func kerning(_ value: CGFloat) -> Self {
attributes[.kern] = value
return self
}
/// 设置链接
@discardableResult
func link(_ url: URL) -> Self {
attributes[.link] = url
return self
}
/// 构建富文本
func build() -> NSAttributedString {
return NSAttributedString(string: string, attributes: attributes)
}
}
//
// UIColor+Extension.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
extension UIColor {
convenience init(hex:UInt32 = 0xFFFFFF , alpha:Double = 1) {
let red = Double((hex & 0xFF0000) >> 16) / 255.0
let green = Double((hex & 0xFF00) >> 8) / 255.0
let blue = Double((hex & 0xFF)) / 255.0
self.init(red: red, green: green, blue: blue, alpha: alpha)
}
convenience init(with Hex:String = "#FFFFFF" , alpha:Double = 1) {
var str = Hex.lowercased()
if (str.hasPrefix("#") && str.count == 7) || (str.hasPrefix("0x") && str.count == 8) {
if str.hasPrefix("#") {
str = String(str[str.index(str.startIndex, offsetBy: 1)...])
}else if str.hasPrefix("0x"){
str = String(str[str.index(str.startIndex, offsetBy: 2)...])
}
var hexInt:UInt64 = 0
Scanner(string: str).scanHexInt64(&hexInt)
let red = Double((hexInt & 0xFF0000) >> 16) / 255.0
let green = Double((hexInt & 0xFF00) >> 8) / 255.0
let blue = Double((hexInt & 0xFF)) / 255.0
self.init(red: red, green: green, blue: blue, alpha: alpha)
}else{
self.init(red: 1, green: 1, blue: 1, alpha: 0)
}
}
}
//
// UILabel+Extension.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
extension UILabel {
@IBInspectable var spacing: CGFloat {
get {
guard let attributedText = self.attributedText,
let paragraphStyle = attributedText.attributes(at: 0, effectiveRange: nil)[.paragraphStyle] as? NSParagraphStyle else {
return 0
}
return paragraphStyle.lineSpacing
}
set {
guard let text = self.text else { return }
if let attributedText = self.attributedText {
let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = newValue
paragraphStyle.alignment = self.textAlignment
mutableAttributedText.addAttribute(.paragraphStyle,
value: paragraphStyle,
range: NSRange(location: 0, length: mutableAttributedText.length))
self.attributedText = mutableAttributedText
} else {
let attributedString = NSMutableAttributedString(string: text)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = newValue
paragraphStyle.alignment = self.textAlignment
attributedString.addAttribute(.paragraphStyle,
value: paragraphStyle,
range: NSRange(location: 0, length: text.count))
self.attributedText = attributedString
}
}
}
}
//
// UIView+Extension.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/2.
//
import UIKit
@IBDesignable
extension UIView {
@objc public var callblack:((Any)->Void)? {
set {
var state = UnsafeRawPointerState.UnsafeCallBack.rawValue
objc_setAssociatedObject(self, &state, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
var state = UnsafeRawPointerState.UnsafeCallBack.rawValue
return objc_getAssociatedObject(self, &state) as? ((Any)->Void)
}
}
@objc private func gestureTouches(_ ches:UIGestureRecognizer) -> Void {
guard let call = callblack else { return }
call(ches)
}
@discardableResult
/// 添加手势
func gesture(gesture:UIView.Gesture,_ complate:((Any)->Void)?) -> UIGestureRecognizer? {
var ges:UIGestureRecognizer?
callblack = complate
switch gesture {
case .tap:
self.gestureRecognizers?.filter({$0 is UITapGestureRecognizer}).forEach({self.removeGestureRecognizer($0)})
ges = UITapGestureRecognizer(target: self, action: #selector(gestureTouches(_:)))
break
case .swipe:
self.gestureRecognizers?.filter({$0 is UISwipeGestureRecognizer}).forEach({self.removeGestureRecognizer($0)})
ges = UISwipeGestureRecognizer(target: self, action: #selector(gestureTouches(_:)))
break
case .long:
self.gestureRecognizers?.filter({$0 is UILongPressGestureRecognizer}).forEach({self.removeGestureRecognizer($0)})
ges = UILongPressGestureRecognizer(target: self, action: #selector(gestureTouches(_:)))
break
case .pan:
self.gestureRecognizers?.filter({$0 is UIPanGestureRecognizer}).forEach({self.removeGestureRecognizer($0)})
ges = UIPanGestureRecognizer(target: self, action: #selector(gestureTouches(_:)))
break
case .pinch:
self.gestureRecognizers?.filter({$0 is UIPinchGestureRecognizer}).forEach({self.removeGestureRecognizer($0)})
ges = UIPinchGestureRecognizer(target: self, action: #selector(gestureTouches(_:)))
break
case .rotation:
self.gestureRecognizers?.filter({$0 is UIRotationGestureRecognizer}).forEach({self.removeGestureRecognizer($0)})
ges = UIRotationGestureRecognizer(target: self, action: #selector(gestureTouches(_:)))
break
case .edgePan:
self.gestureRecognizers?.filter({$0 is UIScreenEdgePanGestureRecognizer}).forEach({self.removeGestureRecognizer($0)})
ges = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(gestureTouches(_:)))
break
}
guard let gesture = ges else { return ges }
self.addGestureRecognizer(gesture)
return gesture
}
/// 添加手势
@discardableResult
public func gesture(target delegate:Any, class gestureCls:UIGestureRecognizer.Type ,selector:Selector) -> UIGestureRecognizer {
let recognizer = gestureCls.init()
self.isUserInteractionEnabled = true
recognizer.addTarget(delegate, action: selector)
self.addGestureRecognizer(recognizer)
return recognizer
}
/// 圆角
@IBInspectable var corners:Double {
set {
self.layer.cornerRadius = newValue
}
get {
return self.layer.cornerRadius
}
}
/// 边框颜色
@IBInspectable var borderColor:UIColor {
set {
self.layer.borderColor = newValue.cgColor
}
get {
return UIColor(cgColor: self.layer.borderColor ?? UIColor.clear.cgColor)
}
}
/// 边框宽度
@IBInspectable var borderWidth:Double {
set {
self.layer.borderWidth = newValue
}
get {
return self.layer.borderWidth
}
}
/** 获取当前控制器 */
func responderCtr() -> UIViewController? {
for view in sequence(first: self.superview, next: { $0?.superview }) {
if let responder = view?.next {
if responder.isKind(of: UIViewController.self){
return responder as? UIViewController
}
}
}
return nil
}
/** 设置圆角 */
public func cornerRect(radius:CGFloat ,_ rectCorner:UIRectCorner) {
let maskPath = UIBezierPath.init(roundedRect: bounds, byRoundingCorners: rectCorner, cornerRadii: CGSize.init(width: radius, height: radius))
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = maskPath.cgPath
layer.mask = maskLayer
}
/** 设置阴影 */
public func shadow(cornerRadius:CGFloat = 4, shadowColor:UIColor = .clear, offset:CGSize = CGSize(width: 0, height: 0), opacity:Float = 1, radius:CGFloat = 0) {
self.layer.masksToBounds = false
self.layer.shadowColor = shadowColor.cgColor
self.layer.shadowOpacity = opacity
self.layer.shadowRadius = radius
self.layer.shadowOffset = offset
self.layer.cornerRadius = cornerRadius
}
enum UnsafeRawPointerState:UInt32 {
case UnsafeCallBack = 0x10000
}
enum Gesture{
case tap
case long
case swipe
case pan
case pinch
case rotation
case edgePan
}
}
/// frame
extension UIView {
var x :CGFloat {
get {
return frame.origin.x
}
set {
var frame1:CGRect = frame
frame1.origin.x = newValue
frame = frame1
}
}
var y :CGFloat {
get {
return frame.origin.y
}
set {
var frame1:CGRect = frame
frame1.origin.y = newValue
frame = frame1
}
}
var width :CGFloat {
get {
return frame.size.width
}
set {
var frame1:CGRect = frame
frame1.size.width = newValue
frame = frame1
}
}
var height :CGFloat {
get {
return frame.size.height
}
set {
var frame1:CGRect = frame
frame1.size.height = newValue
frame = frame1
}
}
var size :CGSize {
get {
return frame.size
}
set {
var frame1:CGRect = frame
frame1.size = newValue
frame = frame1
}
}
var centerX :CGFloat {
get {
return center.x
}
set {
var center1:CGPoint = center
center1.x = newValue
center = center1
}
}
var centerY :CGFloat {
get {
return center.y
}
set {
var center1:CGPoint = center
center1.y = newValue
center = center1
}
}
}
//
// Value+Extension.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
protocol NumericType: Numeric, Comparable, ExpressibleByFloatLiteral {
init(_ value: Double)
var doubleValue:Double { get }
}
extension Float: NumericType {
var doubleValue: Double { Double(self) }
}
extension Double: NumericType {
var doubleValue: Double { Double(self) }
}
extension CGFloat: NumericType {
var doubleValue: Double { Double(self) }
}
extension NumericType {
func adapterW() -> Double {
return self.doubleValue * (Dev.screenW / 375.0)
}
func adapterH() -> Double {
return self.doubleValue * (Dev.screenW / 812.0)
}
}
//
// SpeakEleHomeViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
class SpeakEleHomeViewCtr: SpeakEleBaseViewCtr {
@IBOutlet weak var inputText: UITextField!
@IBOutlet weak var PlayerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
@IBAction func voice(_ sender: Any) {
self.view.layoutIfNeeded()
let text = inputText.text ?? ""
let sub = SpeakVideoPlayer.share.videoPlayer(3.1)
let player = SpeakVideoPlayer.share.players[safe: sub]
let playerLayer = SpeakVideoPlayer.share.playerLayers[safe: sub]
playerLayer?.frame = PlayerView.bounds
PlayerView.layer.addSublayer(playerLayer ?? CALayer())
player?.play()
SpeakSpeechSynthesizer.share.speakText(text)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleHomeViewCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="PlayerView" destination="BpM-GJ-E6Q" id="aZp-Su-jpC"/>
<outlet property="inputText" destination="hZO-Fd-dgW" id="pMk-QA-tkf"/>
<outlet property="view" destination="Ia2-3z-Nib" id="Fy8-sN-P1j"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="Ia2-3z-Nib">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="I have achieved academic success and will go global" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hZO-Fd-dgW">
<rect key="frame" x="0.0" y="401" width="393" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="MPE-Lf-ewE"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" systemColor="labelColor"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="corners">
<real key="value" value="6"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textField>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BpM-GJ-E6Q">
<rect key="frame" x="0.0" y="0.0" width="393" height="452"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="f9P-fF-oCz">
<rect key="frame" x="159" y="474" width="75" height="35"/>
<state key="normal" title="Button"/>
<buttonConfiguration key="configuration" style="plain" title="Button"/>
<connections>
<action selector="voice:" destination="-1" eventType="touchUpInside" id="Oir-5p-BbV"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="rqH-oW-agY"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="hZO-Fd-dgW" firstAttribute="leading" secondItem="BpM-GJ-E6Q" secondAttribute="leading" id="3hk-NC-Oax"/>
<constraint firstAttribute="bottom" secondItem="BpM-GJ-E6Q" secondAttribute="bottom" constant="400" id="8g8-qI-QNB"/>
<constraint firstItem="f9P-fF-oCz" firstAttribute="centerX" secondItem="Ia2-3z-Nib" secondAttribute="centerX" id="GV3-nT-lr2"/>
<constraint firstItem="rqH-oW-agY" firstAttribute="trailing" secondItem="BpM-GJ-E6Q" secondAttribute="trailing" id="Psr-Sd-Wxc"/>
<constraint firstItem="hZO-Fd-dgW" firstAttribute="centerY" secondItem="Ia2-3z-Nib" secondAttribute="centerY" id="cX7-Vj-slv"/>
<constraint firstItem="BpM-GJ-E6Q" firstAttribute="top" secondItem="Ia2-3z-Nib" secondAttribute="top" id="cfj-21-07u"/>
<constraint firstItem="BpM-GJ-E6Q" firstAttribute="leading" secondItem="rqH-oW-agY" secondAttribute="leading" id="hN5-j8-6Gi"/>
<constraint firstItem="hZO-Fd-dgW" firstAttribute="trailing" secondItem="BpM-GJ-E6Q" secondAttribute="trailing" id="r5v-5u-5mI"/>
<constraint firstItem="f9P-fF-oCz" firstAttribute="top" secondItem="hZO-Fd-dgW" secondAttribute="bottom" constant="23" id="vCF-bl-BqC"/>
</constraints>
<point key="canvasLocation" x="519.84732824427476" y="-37.323943661971832"/>
</view>
</objects>
<resources>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// SpeakEleSetViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/3.
//
import UIKit
class SpeakEleSetViewCtr: SpeakEleBaseViewCtr {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
</dependencies>
<scenes/>
</document>
//
// SpeakLottieObjc.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/8.
//
import UIKit
import Lottie
class SpeakLottieObjc: NSObject {
class func loadLottie(_ file:String) -> LottieAnimationView {
let animationView = LottieAnimationView(name: file)
animationView.loopMode = .loop
return animationView
}
}
//
// SpeakSpeechSynthesizer.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/7.
//
import UIKit
import AVFAudio
class SpeakSpeechSynthesizer : NSObject,AVSpeechSynthesizerDelegate {
static let share = SpeakSpeechSynthesizer()
private var synthesizer = AVSpeechSynthesizer()
func speakText(_ text:String) {
guard text.count > 0 else { return }
let utterance = AVSpeechUtterance(string: text)
utterance.voice = AVSpeechSynthesisVoice.speechVoices().first //AVSpeechSynthesisVoice(language: "en-US")
utterance.rate = 0.5
utterance.volume = 1
// 设置动画监听
synthesizer.delegate = self
synthesizer.speak(utterance)
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
// 朗读完成,恢复Idle动画
DispatchQueue.main.async {
Print("结束\(CACurrentMediaTime())")
}
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
// 可以在这里根据朗读进度切换不同的动画
// let progress = Double(characterRange.location) / Double(utterance.speechString.count)
// if progress > 0.7 {
// Print("0.7")
// }
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
Print("开始\(CACurrentMediaTime())")
}
}
//
// SpeakVideoPlayer.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/7.
//
import UIKit
import AVFoundation
class SpeakVideoPlayer {
var players: [AVPlayer] = []
var playerLayers: [AVPlayerLayer] = []
static let share = SpeakVideoPlayer()
open func videoPlayer(_ rate:Double = 0) -> Int {
var sets:(Int,Double) = (0,0.0)
switch rate {
case 0...5:
sets.0 = 0
sets.1 = 4/rate
break
case 6..<10:
break
case 10...15:
sets.0 = 1
sets.1 = 12/rate
break
case 35...45:
sets.0 = 2
sets.1 = 40/rate
break
default:
break
}
players[sets.0].rate = Float(sets.1)
players[sets.0].play()
return sets.0
}
private init() {
let videos = ["测试2-5[4s]","测试10-15[12s]","测试35-45[40s]"]
var urls:[URL] = []
for name in videos {
if let path = Bundle.main.path(forResource: name, ofType: ".mp4") {
let url = URL(fileURLWithPath: path)
urls.append(url)
}
}
self.setupPlayers(videoURLs: urls)
}
// 初始化多个视频播放器
private func setupPlayers(videoURLs: [URL]) {
// 为每个视频创建播放器
for (_, url) in videoURLs.enumerated() {
let playerItem = AVPlayerItem(url: url)
let player = AVPlayer(playerItem: playerItem)
players.append(player)
// 创建对应的图层
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspectFill
playerLayer.shouldRasterize = true
playerLayer.rasterizationScale = UIScreen.main.nativeScale
playerLayers.append(playerLayer)
// 设置循环播放
NotificationCenter.default.addObserver(
forName: .AVPlayerItemDidPlayToEndTime,
object: playerItem,
queue: .main
) { [weak player] _ in
player?.seek(to: .zero)
// player?.play()
}
}
}
func playAll() {
players.forEach { $0.play() }
}
func pauseAll() {
players.forEach { $0.pause() }
}
deinit {
players.forEach { $0.pause() }
NotificationCenter.default.removeObserver(self)
}
}
<?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>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment