add app for iOS

This commit is contained in:
Maciej Czajka 2023-01-27 00:11:51 +01:00
parent 167f0b4487
commit 12340b87e5
26 changed files with 1483 additions and 67 deletions

View File

@ -0,0 +1,457 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objects = {
/* Begin PBXBuildFile section */
52A4E0F72982BC4300C09B44 /* ImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4E0F62982BC4300C09B44 /* ImagePicker.swift */; };
52A4E0FD2982F76800C09B44 /* ResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4E0FC2982F76800C09B44 /* ResultView.swift */; };
52A4E0FF29830C2D00C09B44 /* LoaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4E0FE29830C2D00C09B44 /* LoaderView.swift */; };
52A4E10129830C6200C09B44 /* WaitData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4E10029830C6200C09B44 /* WaitData.swift */; };
52A4E103298312BC00C09B44 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4E102298312BC00C09B44 /* MenuView.swift */; };
52A4E1052983133200C09B44 /* PlatesListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4E1042983133200C09B44 /* PlatesListView.swift */; };
52A4E10E2983166400C09B44 /* PlatesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4E10D2983166400C09B44 /* PlatesList.swift */; };
52A4E11029831B5000C09B44 /* LicensePlateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4E10F29831B5000C09B44 /* LicensePlateItem.swift */; };
52F7EB5129814DC600125573 /* LicensePlatesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F7EB5029814DC600125573 /* LicensePlatesApp.swift */; };
52F7EB5329814DC600125573 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F7EB5229814DC600125573 /* ContentView.swift */; };
52F7EB5529814DC700125573 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52F7EB5429814DC700125573 /* Assets.xcassets */; };
52F7EB5829814DC700125573 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52F7EB5729814DC700125573 /* Preview Assets.xcassets */; };
52F7EB5F2981510800125573 /* ResponseItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F7EB5E2981510800125573 /* ResponseItem.swift */; };
52F7EB612981516000125573 /* Api.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F7EB602981516000125573 /* Api.swift */; };
52F7EB642981519300125573 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 52F7EB632981519300125573 /* Alamofire */; };
52F7EB66298151B800125573 /* ResponseData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F7EB65298151B800125573 /* ResponseData.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
52A4E0F62982BC4300C09B44 /* ImagePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePicker.swift; sourceTree = "<group>"; };
52A4E0FC2982F76800C09B44 /* ResultView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultView.swift; sourceTree = "<group>"; };
52A4E0FE29830C2D00C09B44 /* LoaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoaderView.swift; sourceTree = "<group>"; };
52A4E10029830C6200C09B44 /* WaitData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitData.swift; sourceTree = "<group>"; };
52A4E102298312BC00C09B44 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = "<group>"; };
52A4E1042983133200C09B44 /* PlatesListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatesListView.swift; sourceTree = "<group>"; };
52A4E10D2983166400C09B44 /* PlatesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatesList.swift; sourceTree = "<group>"; };
52A4E10F29831B5000C09B44 /* LicensePlateItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensePlateItem.swift; sourceTree = "<group>"; };
52F7EB4D29814DC600125573 /* LicensePlates.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LicensePlates.app; sourceTree = BUILT_PRODUCTS_DIR; };
52F7EB5029814DC600125573 /* LicensePlatesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LicensePlatesApp.swift; sourceTree = "<group>"; };
52F7EB5229814DC600125573 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
52F7EB5429814DC700125573 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
52F7EB5729814DC700125573 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
52F7EB5E2981510800125573 /* ResponseItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseItem.swift; sourceTree = "<group>"; };
52F7EB602981516000125573 /* Api.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Api.swift; sourceTree = "<group>"; };
52F7EB65298151B800125573 /* ResponseData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseData.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
52F7EB4A29814DC600125573 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
52F7EB642981519300125573 /* Alamofire in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
52A4E1062983156600C09B44 /* View */ = {
isa = PBXGroup;
children = (
52A4E102298312BC00C09B44 /* MenuView.swift */,
52F7EB5229814DC600125573 /* ContentView.swift */,
52A4E0FC2982F76800C09B44 /* ResultView.swift */,
52A4E1042983133200C09B44 /* PlatesListView.swift */,
52A4E0FE29830C2D00C09B44 /* LoaderView.swift */,
);
path = View;
sourceTree = "<group>";
};
52A4E1072983158900C09B44 /* Model */ = {
isa = PBXGroup;
children = (
52F7EB5E2981510800125573 /* ResponseItem.swift */,
52A4E10F29831B5000C09B44 /* LicensePlateItem.swift */,
);
path = Model;
sourceTree = "<group>";
};
52A4E1082983159400C09B44 /* Data */ = {
isa = PBXGroup;
children = (
52A4E10D2983166400C09B44 /* PlatesList.swift */,
52F7EB65298151B800125573 /* ResponseData.swift */,
52A4E10029830C6200C09B44 /* WaitData.swift */,
);
path = Data;
sourceTree = "<group>";
};
52A4E109298315A400C09B44 /* Another */ = {
isa = PBXGroup;
children = (
52A4E0F62982BC4300C09B44 /* ImagePicker.swift */,
);
path = Another;
sourceTree = "<group>";
};
52A4E10C2983164C00C09B44 /* Controller */ = {
isa = PBXGroup;
children = (
52F7EB602981516000125573 /* Api.swift */,
);
path = Controller;
sourceTree = "<group>";
};
52F7EB4429814DC600125573 = {
isa = PBXGroup;
children = (
52F7EB4F29814DC600125573 /* LicensePlates */,
52F7EB4E29814DC600125573 /* Products */,
);
sourceTree = "<group>";
};
52F7EB4E29814DC600125573 /* Products */ = {
isa = PBXGroup;
children = (
52F7EB4D29814DC600125573 /* LicensePlates.app */,
);
name = Products;
sourceTree = "<group>";
};
52F7EB4F29814DC600125573 /* LicensePlates */ = {
isa = PBXGroup;
children = (
52F7EB5029814DC600125573 /* LicensePlatesApp.swift */,
52A4E1062983156600C09B44 /* View */,
52A4E10C2983164C00C09B44 /* Controller */,
52A4E1082983159400C09B44 /* Data */,
52A4E1072983158900C09B44 /* Model */,
52A4E109298315A400C09B44 /* Another */,
52F7EB5429814DC700125573 /* Assets.xcassets */,
52F7EB5629814DC700125573 /* Preview Content */,
);
path = LicensePlates;
sourceTree = "<group>";
};
52F7EB5629814DC700125573 /* Preview Content */ = {
isa = PBXGroup;
children = (
52F7EB5729814DC700125573 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
52F7EB4C29814DC600125573 /* LicensePlates */ = {
isa = PBXNativeTarget;
buildConfigurationList = 52F7EB5B29814DC700125573 /* Build configuration list for PBXNativeTarget "LicensePlates" */;
buildPhases = (
52F7EB4929814DC600125573 /* Sources */,
52F7EB4A29814DC600125573 /* Frameworks */,
52F7EB4B29814DC600125573 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = LicensePlates;
packageProductDependencies = (
52F7EB632981519300125573 /* Alamofire */,
);
productName = LicensePlates;
productReference = 52F7EB4D29814DC600125573 /* LicensePlates.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
52F7EB4529814DC600125573 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1420;
LastUpgradeCheck = 1420;
TargetAttributes = {
52F7EB4C29814DC600125573 = {
CreatedOnToolsVersion = 14.2;
};
};
};
buildConfigurationList = 52F7EB4829814DC600125573 /* Build configuration list for PBXProject "LicensePlates" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 52F7EB4429814DC600125573;
packageReferences = (
52F7EB622981519300125573 /* XCRemoteSwiftPackageReference "Alamofire" */,
);
productRefGroup = 52F7EB4E29814DC600125573 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
52F7EB4C29814DC600125573 /* LicensePlates */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
52F7EB4B29814DC600125573 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
52F7EB5829814DC700125573 /* Preview Assets.xcassets in Resources */,
52F7EB5529814DC700125573 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
52F7EB4929814DC600125573 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
52A4E10E2983166400C09B44 /* PlatesList.swift in Sources */,
52F7EB5329814DC600125573 /* ContentView.swift in Sources */,
52F7EB5F2981510800125573 /* ResponseItem.swift in Sources */,
52F7EB66298151B800125573 /* ResponseData.swift in Sources */,
52A4E0F72982BC4300C09B44 /* ImagePicker.swift in Sources */,
52F7EB612981516000125573 /* Api.swift in Sources */,
52A4E103298312BC00C09B44 /* MenuView.swift in Sources */,
52A4E0FF29830C2D00C09B44 /* LoaderView.swift in Sources */,
52A4E10129830C6200C09B44 /* WaitData.swift in Sources */,
52A4E1052983133200C09B44 /* PlatesListView.swift in Sources */,
52A4E0FD2982F76800C09B44 /* ResultView.swift in Sources */,
52F7EB5129814DC600125573 /* LicensePlatesApp.swift in Sources */,
52A4E11029831B5000C09B44 /* LicensePlateItem.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
52F7EB5929814DC700125573 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
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;
GCC_C_LANGUAGE_STANDARD = gnu11;
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 = 16.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
52F7EB5A29814DC700125573 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
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;
GCC_C_LANGUAGE_STANDARD = gnu11;
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 = 16.2;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
52F7EB5C29814DC700125573 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"LicensePlates/Preview Content\"";
DEVELOPMENT_TEAM = VKJ3MY4S58;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maciejczajka.LicensePlates;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
52F7EB5D29814DC700125573 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"LicensePlates/Preview Content\"";
DEVELOPMENT_TEAM = VKJ3MY4S58;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maciejczajka.LicensePlates;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
52F7EB4829814DC600125573 /* Build configuration list for PBXProject "LicensePlates" */ = {
isa = XCConfigurationList;
buildConfigurations = (
52F7EB5929814DC700125573 /* Debug */,
52F7EB5A29814DC700125573 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
52F7EB5B29814DC700125573 /* Build configuration list for PBXNativeTarget "LicensePlates" */ = {
isa = XCConfigurationList;
buildConfigurations = (
52F7EB5C29814DC700125573 /* Debug */,
52F7EB5D29814DC700125573 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
52F7EB622981519300125573 /* XCRemoteSwiftPackageReference "Alamofire" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/Alamofire/Alamofire.git";
requirement = {
branch = master;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
52F7EB632981519300125573 /* Alamofire */ = {
isa = XCSwiftPackageProductDependency;
package = 52F7EB622981519300125573 /* XCRemoteSwiftPackageReference "Alamofire" */;
productName = Alamofire;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 52F7EB4529814DC600125573 /* Project object */;
}

View File

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

View File

@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire.git",
"state" : {
"branch" : "master",
"revision" : "f1f7a06f40c6aadb4beb2a78f380f9938d574fa7"
}
}
],
"version" : 2
}

View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "D6BB566A-C242-4B4E-B55F-1FA78A3A061D"
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "C405232E-BB0E-451D-8446-9D77C6D5C242"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/Api.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "44"
endingLineNumber = "44"
landmarkName = "getImageResponse(image:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "964C614A-2A94-484B-995D-37E1EA3A1EE9"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/Api.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "47"
endingLineNumber = "47"
landmarkName = "getImageResponse(image:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "E81E0E46-48E0-405F-A7FF-B15E52AACF61"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/Api.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "48"
endingLineNumber = "48"
landmarkName = "getImageResponse(image:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "3F7BADFC-0310-4A3D-ABF6-997289009860"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/Api.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "52"
endingLineNumber = "52"
landmarkName = "getImageResponse(image:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "DC86FA00-5B66-447C-929B-FD55AF8266F0"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/Api.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "76"
endingLineNumber = "76"
landmarkName = "getImageResponse(image:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "24FB4CBE-0AAC-4DDA-AEA0-76F900B07C5D"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/Api.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "45"
endingLineNumber = "45"
landmarkName = "getImageResponse(image:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "7895A366-749C-44A0-80F9-DBE283BC0589"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/ContentView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "169"
endingLineNumber = "169"
landmarkName = "loadImage()"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "2A9DA0ED-54FE-4874-AF3B-2CDDC1E23236"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/ContentView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "170"
endingLineNumber = "170"
landmarkName = "loadImage()"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "90B92D30-3422-4395-9985-B40318AFD8D8"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/Controller/Api.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "62"
endingLineNumber = "62"
landmarkName = "getImageResponse(image:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "8D991345-46AE-480A-9AB9-76AC3F3EC043"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "LicensePlates/Controller/Api.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "66"
endingLineNumber = "66"
landmarkName = "getImageResponse(image:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

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

View File

@ -0,0 +1,187 @@
//
// ImagePicker.swift
// LicensePlates
//
// Created by Maciej Czajka on 26/01/2023.
//
import SwiftUI
import PhotosUI
import UIKit
struct ImagePicker: UIViewControllerRepresentable {
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.image = uiImage
}
parent.presentationMode.wrappedValue.dismiss()
}
}
@Environment(\.presentationMode) var presentationMode
@Binding var image: UIImage?
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
// nop
}
}
struct CameraPicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: UIImage?
@Environment(\.presentationMode) var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraPicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = sourceType
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<CameraPicker>) {
// nop
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: CameraPicker
init(_ parent: CameraPicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.originalImage] as? UIImage {
parent.selectedImage = image
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
//struct CameraPicker: UIViewControllerRepresentable {
//
// var sourceType: UIImagePickerController.SourceType = .photoLibrary
//
// @Binding var selectedImage: [UIImage]
// @Environment(\.presentationMode) private var presentationMode
//
// func makeUIViewController(context: UIViewControllerRepresentableContext<CameraPicker>) -> UIImagePickerController {
//
// let imagePicker = UIImagePickerController()
// imagePicker.allowsEditing = false
// imagePicker.sourceType = sourceType
// imagePicker.delegate = context.coordinator
//
// return imagePicker
// }
//
// func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<CameraPicker>) {
//
// }
//
// func makeCoordinator() -> Coordinator {
// Coordinator(self)
// }
//
// final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//
// var parent: CameraPicker
//
// init(_ parent: CameraPicker) {
// self.parent = parent
// }
//
// func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//
// if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
// parent.selectedImage.append(image)
// }
//
// parent.presentationMode.wrappedValue.dismiss()
// }
// }
//}
//
//struct ImagePicker: UIViewControllerRepresentable {
// func makeCoordinator() -> Coordinator {
// return ImagePicker.Coordinator(self)
// }
//
//
// @Binding var images: [UIImage]
// @Binding var picker: Bool
//
// func makeUIViewController(context: Context) -> PHPickerViewController {
// var config = PHPickerConfiguration()
// config.filter = .images
// config.selectionLimit = 0
// let picker = PHPickerViewController(configuration: config)
// picker.delegate = context.coordinator
// return picker
// }
//
// func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
// // nop
// }
//
// class Coordinator: NSObject, PHPickerViewControllerDelegate {
// let parent: ImagePicker
//
// init(_ parent1: ImagePicker) {
// self.parent = parent1
// }
//
// func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// parent.picker.toggle()
// for img in results {
// if img.itemProvider.canLoadObject(ofClass: UIImage.self) {
// img.itemProvider.loadObject(ofClass: UIImage.self) { (image, error) in
// guard let image1 = image else {
// print(error)
// return
// }
//// DispatchQueue.main.async {
//// self.parent.images.append(image as! UIImage)
//// }
// self.parent.images.append(image as! UIImage)
//
// }
// } else {
// print("cannot be loaded")
// }
// }
// }
// }
//}

View File

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

View File

@ -0,0 +1,13 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

View File

@ -0,0 +1,96 @@
//
// Api.swift
// LicensePlates
//
// Created by Maciej Czajka on 25/01/2023.
//
import Foundation
import Alamofire
import SwiftUI
let evaluators:[String:ServerTrustEvaluating]=[
"http://192.168.5.129:8080":DisabledTrustEvaluator()
]
let manager=ServerTrustManager(evaluators: evaluators)
let session=Session.init(serverTrustManager:manager)
class Api {
func getResponse(completion: @escaping(Bool?) -> Void) {
session.request("http://192.168.5.129:8080/test",method:.get, encoding: JSONEncoding.default).response { response in
switch response.result {
case.success:
if response.response?.statusCode == 200 {
let jsonData = response.data
do {
let allReplies = try JSONDecoder().decode(RepsonseItem.self, from: jsonData!)
ResponseData.shared.str = allReplies.str
completion(true)
} catch {
print("Error: \(error)")
completion(false)
}
}
else { completion(false) }
case.failure:
completion(false)
}
}
}
func getImageResponse(image: String, completion: @escaping(Bool?) -> Void) {
let parameters = ["imageFile": image] as [String : Any]
session.request("http://192.168.5.129:8080/detectLicense", method: .post, parameters: parameters as Parameters, encoding: JSONEncoding.default, headers: nil)
.response { response in
switch response.result {
case.success:
if response.response?.statusCode == 200 {
var responseData = ""
do {
responseData = try JSONDecoder().decode(String.self, from: response.data!)
if responseData != "None" {
responseData = responseData.replacingOccurrences(of: "b'", with: "")
responseData = String(responseData.replacingOccurrences(of: "\'", with: ""))
responseData = responseData.fixedBase64Format
let myUIImage = responseData.imageFromBase64
let image = Image(uiImage: myUIImage!)
ResponseData.shared.imageData = image
PlatesList.shared.imagesList.append(LicensePlateItem(image: image))
// using UserDefaults
// PlatesList.shared.imagesBase64List.append(myUIImage!.base64!)
// UserDefaults.standard.set(PlatesList.shared.imagesBase64List, forKey: "platesList")
ResponseData.shared.uiImageData = myUIImage!
completion(true)
} else {
completion(false)
}
} catch {
print("Error: \(error)")
completion(false)
}
} else {
completion(false)
}
case.failure:
completion(false)
}
}
}
}
extension String {
var fixedBase64Format: Self {
let offset = count % 4
guard offset != 0 else { return self }
return padding(toLength: count + 4 - offset, withPad: "=", startingAt: 0)
}
}

View File

@ -0,0 +1,17 @@
//
// PlatesList.swift
// LicensePlates
//
// Created by Maciej Czajka on 26/01/2023.
//
import Foundation
import SwiftUI
class PlatesList : ObservableObject {
@Published var imagesList: [LicensePlateItem] = [LicensePlateItem]()
// using UserDefaults
// @Published var imagesBase64List: [String] = UserDefaults.standard.stringArray(forKey: "platesList") ?? [String]()
static let shared = PlatesList()
}

View File

@ -0,0 +1,17 @@
//
// ResponseData.swift
// LicensePlates
//
// Created by Maciej Czajka on 25/01/2023.
//
import Foundation
import SwiftUI
class ResponseData: ObservableObject {
@Published var str: String = ""
@Published var imageData: Image = Image(systemName: "trash")
@Published var uiImageData: UIImage = UIImage()
static let shared = ResponseData()
}

View File

@ -0,0 +1,14 @@
//
// WaitData.swift
// LicensePlates
//
// Created by Maciej Czajka on 26/01/2023.
//
import Foundation
class Wait: ObservableObject {
@Published var wait: Bool = false
static let shared = Wait()
}

View File

@ -0,0 +1,17 @@
//
// LicensePlatesApp.swift
// LicensePlates
//
// Created by Maciej Czajka on 25/01/2023.
//
import SwiftUI
@main
struct LicensePlatesApp: App {
var body: some Scene {
WindowGroup {
MenuView()
}
}
}

View File

@ -0,0 +1,14 @@
//
// LicensePlateItem.swift
// LicensePlates
//
// Created by Maciej Czajka on 26/01/2023.
//
import Foundation
import SwiftUI
struct LicensePlateItem {
var id = UUID()
var image: Image
}

View File

@ -0,0 +1,12 @@
//
// responseItem.swift
// LicensePlates
//
// Created by Maciej Czajka on 25/01/2023.
//
import Foundation
struct RepsonseItem: Codable {
let str: String
}

View File

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

View File

@ -0,0 +1,199 @@
//
// ContentView.swift
// LicensePlates
//
// Created by Maciej Czajka on 25/01/2023.
//
import SwiftUI
import AVFoundation
struct ContentView: View {
@Environment(\.presentationMode) var presentationMode
@Environment(\.colorScheme) var colorScheme
@ObservedObject var item = ResponseData.shared
@ObservedObject var wait = Wait.shared
@State private var image: Image?
@State private var showingImagePicker = false
@State private var showingCameraPicker = false
@State private var isCameraAccessEnabled = false
@State public var inputImage: UIImage?
@State private var disabledButton = true
@State private var isPresented = false
@State private var notDetected = false
@State private var selection: String? = nil
private let apiManager = Api()
var body: some View {
ZStack {
NavigationView {
VStack {
NavigationLink(destination: ResultView(), tag: "Success", selection: $selection) { EmptyView() }
Spacer()
if image != nil {
HStack {
Spacer()
image?.resizable()
.scaledToFit()
.cornerRadius(10)
.padding(.bottom, 10)
.onTapGesture {
openCamera()
}
Image(systemName: "minus.circle")
.foregroundColor(Color(.red))
.padding(5)
.onTapGesture {
withAnimation(.easeOut) {
image = nil
inputImage = nil
disabledButton = true
}
}
Spacer()
}
} else {
HStack {
Spacer()
VStack {
Image(systemName: "plus.circle.fill")
.font(.system(size: 40))
.foregroundColor(Color(colorScheme == .dark ? .white : .black))
.padding(.top, 5)
.onTapGesture {
self.showingImagePicker = true
}
.padding()
Text("Choose a photo\n from the library")
.multilineTextAlignment(.center)
}
Spacer()
VStack {
Image(systemName: "camera.fill")
.font(.system(size: 40))
.foregroundColor(Color(colorScheme == .dark ? .white : .black))
.padding(.top, 5)
.onTapGesture {
isPresented.toggle()
}
.padding()
Text("Take a photo\n with a camera")
.multilineTextAlignment(.center)
}
Spacer()
}
.padding()
}
if disabledButton == false {
Button {
wait.wait = true
apiManager.getImageResponse(image: inputImage!.base64!) { res in
if res == true {
selection = "Success"
wait.wait = false
image = nil
inputImage = nil
disabledButton = true
} else {
wait.wait = false
notDetected.toggle()
image = nil
inputImage = nil
disabledButton = true
}
}
} label: {
Text("Detect license plate")
}
.disabled(disabledButton)
.padding(.horizontal, 30)
.padding(.vertical, 5)
// .background(Color(colorScheme == .dark ? .white : .black))
.cornerRadius(40)
.foregroundColor(Color(colorScheme == .dark ? .white : .black))
.padding(5)
.overlay(RoundedRectangle(cornerRadius: 40).stroke(Color(colorScheme == .dark ? .white : .black), lineWidth: 2.0))
.padding()
}
Spacer()
}
.alert("Please take a photo horizontally", isPresented: $isPresented) {
Button("OK", role: .cancel) {
openCamera()
}
}
.alert("No license plate detected, find another photo", isPresented: $notDetected) {
Button("OK", role: .cancel) {
// do nothing
}
}
}
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage) {
ImagePicker(image: self.$inputImage)
}
.sheet(isPresented: $showingCameraPicker, onDismiss: loadImage) {
CameraPicker(sourceType: .camera, selectedImage: self.$inputImage)
}
if wait.wait {
GeometryReader { _ in
LoaderView().frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
}
.background(Color.black.opacity(0.45))
.edgesIgnoringSafeArea(.all)
}
}
}
private func openCamera() {
if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
self.showingCameraPicker = true
} else if AVCaptureDevice.authorizationStatus(for: .video) == .notDetermined {
self.showingCameraPicker = true
} else {
self.isCameraAccessEnabled = true
}
}
func loadImage() {
guard let inputImage = inputImage else { return }
image = Image(uiImage: inputImage)
disabledButton = false
}
func convertImageToBase64String(inputImage: UIImage?) -> String {
guard let imageData = inputImage?.jpegData(compressionQuality: 0.3) else { return ""}
let res = imageData.base64EncodedString()
return res
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension UIImage {
var base64: String? {
self.jpegData(compressionQuality: 1)?.base64EncodedString()
}
}
extension String {
var imageFromBase64: UIImage? {
guard let imageData = Data(base64Encoded: self, options: .ignoreUnknownCharacters) else {
return nil
}
return UIImage(data: imageData)
}
}

View File

@ -0,0 +1,25 @@
import SwiftUI
struct LoaderView: View {
@State var animate: Bool = false
var body: some View {
VStack{
Circle()
.trim(from: 0.025, to: 0.82)
.stroke(AngularGradient(gradient: .init(colors: [Color(.white), Color(.white)]), center: .center), style: StrokeStyle(lineWidth: 8, lineCap: .round))
.frame(width: 45, height: 45)
.rotationEffect(.init(degrees: self.animate ? 360 : 0))
.animation(Animation.linear(duration: 0.7).repeatForever(autoreverses: false))
}
.background(Color.clear)
.onAppear { self.animate.toggle() }
}
}
struct Loader_Previews: PreviewProvider {
static var previews: some View {
LoaderView()
}
}

View File

@ -0,0 +1,32 @@
//
// MenuView.swift
// LicensePlates
//
// Created by Maciej Czajka on 26/01/2023.
//
import SwiftUI
struct MenuView: View {
var body: some View {
TabView {
ContentView()
.tabItem {
Image(systemName: "viewfinder")
Text("Photo")
}
PlatesListView()
.tabItem {
Image(systemName: "list.dash")
Text("History")
}
}
.accentColor(Color(.white))
}
}
struct MenuView_Previews: PreviewProvider {
static var previews: some View {
MenuView()
}
}

View File

@ -0,0 +1,81 @@
//
// CodesListView.swift
// Scanner
//
// Created by Maciej Czajka on 08/11/2021.
//
import SwiftUI
struct PlatesListView: View {
@ObservedObject var imagesList = PlatesList.shared
@State var isPresented: Bool = false
var body: some View {
NavigationView {
VStack {
if imagesList.imagesList.isEmpty {
Text("No history")
} else {
List {
ForEach(imagesList.imagesList, id: \.id) { item in
item.image
.resizable()
.scaledToFit()
.padding()
}
}
}
}
// using UserDefaults
// VStack {
// if imagesList.imagesBase64List.isEmpty {
// Text("No history")
// } else {
// List {
// ForEach(imagesList.imagesBase64List, id: \.self) { item in
// Image(uiImage: item.imageFromBase64!)
// .resizable()
// .scaledToFit()
// .padding()
//
// }
// }
//
// }
// }
// using UserDefaults
// .toolbar {
// ToolbarItem(placement: .navigationBarLeading) {
// Button {
// isPresented.toggle()
// } label: {
// Image(systemName: "trash")
// }
// }
// }
}
// using UserDefaults
// .alert(isPresented: $isPresented, content: {
// Alert(title: Text("Do you want to delete the history?"),
// primaryButton: .default(Text("No")){
// },
// secondaryButton:.default(Text("Yes")) {
// UserDefaults.standard.set([String](), forKey: "platesList")
//// imagesList.imagesBase64List = UserDefaults.standard.stringArray(forKey: "platesList") ?? [String]()
// })
// })
}
}
struct PlatesListView_Previews: PreviewProvider {
static var previews: some View {
PlatesListView()
}
}

View File

@ -0,0 +1,31 @@
//
// ResultView.swift
// LicensePlates
//
// Created by Maciej Czajka on 26/01/2023.
//
import SwiftUI
struct ResultView: View {
@ObservedObject var responseData = ResponseData.shared
@State var lastScaleValue: CGFloat = 1.0
var body: some View {
if responseData.imageData != Image(systemName: "trash" ) {
Spacer()
responseData.imageData
.resizable()
.scaledToFit()
.padding()
Spacer()
}
}
}
struct ResultView_Previews: PreviewProvider {
static var previews: some View {
ResultView()
}
}

58
api.py
View File

@ -1,40 +1,50 @@
# python -m pip install flask
# export FLASK_APP=main.py
# export FLASK_APP=api.py
# flask run --without-threads
from flask import Flask, request
from flask import Flask, request, jsonify
from yolo import YOLO
import json
import yolo_video
import base64
import cv2 as cv
app = Flask(__name__)
""" Automatic call while FLASK init """
yolo_model = YOLO()
# def deinit_yolo(yolo):
# yolo.close_session()
"""API_address/ping/<int:id>"""
@app.route("/ping/<int:id>", methods=["GET"])
def get_ping(id: int):
print(f'Request for PING {id=} received')
id = id + 1
return jsonify(id), 200
"""API_address/test"""
@app.get("/test")
def test():
o = {'str': 'okokok'}
return jsonify(o), 200
"""API_address/detectLicense?img="""
@app.get("/detectLicense")
@app.route("/detectLicense", methods=['POST'])
def detectLicensePlate():
# build path
image_path = request.args['img']
# decoded_data = base64.b64decode((image_base64))
# img_file = open('img_to_detect.png', 'wb')
# img_file.write(decoded_data)
# img_file.close()
# P8080275.JPG
# image_path = 'img_to_detect.png'
image_path = './Images/' + image_path
str = yolo_video.detect_license_plate(model=yolo_model, img_path=image_path)
yolo_model = YOLO()
res = json.loads(request.data)
print('ok')
if not base64:
return {
'str': ["None"],
}, 200
# decoded data
decoded_data = base64.b64decode(res["imageFile"])
img_file = open('base64.png', 'wb')
img_file.write(decoded_data)
img_file.close()
image_path = r'base64.png'
base64_b = yolo_video.detect_license_plate(model=yolo_model, img_path=image_path, i=0)
print(type(str(base64_b)))
res = {'str': str(base64_b)}
return jsonify(str(base64_b)), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
else:
return {
'str': str,
}, 200

View File

@ -86,33 +86,15 @@ def detect_img(yolo, img_path, j):
y2 = prediction[2][1]
w = abs(x1 - x2)
h = abs(y1 - y2)
# print(pred)
# print(f'x1: {x1}, x2: {x2}, y1: {y1}, y2: {y2}, w: {w}, h: {h}')
img = processed_image[y1:y1 + h, x1:x1 + w]
img = deskew(img)
# gray_image = cv.cvtColor(robot_img, cv.COLOR_BGR2GRAY)
# # gray_image = cv.bilateralFilter(gray_image, 11, 17, 17)
# gaussian_blur = cv.GaussianBlur(gray_image, (9, 9), 0)
# edged = cv.Canny(gaussian_blur, 255, 255)
#
# image_file = './img0.png'
# img = cv.imread(image_file)
gray_image = grayscale(img)
thresh, im_bw = cv.threshold(gray_image, 125, 150, cv.THRESH_BINARY) #the best = 120,150; 100, 150; 150, 210
thresh, im_bw = cv.threshold(gray_image, 125, 150, cv.THRESH_BINARY)
no_noise = noise_removal(im_bw)
no_borders = remove_borders(no_noise)
# blur = cv.GaussianBlur(gray_image, (3, 3), 0)
# thresh = cv.threshold(blur, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
#
# # Morph open to remove noise and invert image
# kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
# opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=1)
# no_borders = 255 - no_borders
cv.imwrite(f'img/img{j}{i}.png', no_borders)
text = ocr.get_text_from_image(f'img/img{j}{i}.png')
if i > 0:
@ -122,35 +104,13 @@ def detect_img(yolo, img_path, j):
cv.imwrite(f'final/final{j}{i}.png', res)
my_string = 'ok'
i += 1
# with open("final.png", "rb") as img_file:
# my_string = base64.b64encode(img_file.read())
# print(my_string)
with open(f"final/final{j}{i-1}.png", "rb") as img_file:
my_string = base64.b64encode(img_file.read())
return my_string
# text_file = open("base64.txt", "w")
# text_file.write(str(my_string))
# text_file.close()
# decoded data
# decoded_data = base64.b64decode((my_string))
# img_file = open('base64.png', 'wb')
# img_file.write(decoded_data)
# img_file.close()
def detect_license_plate(model, img_path, i):
str = detect_img(model, img_path, i)
if not str:
return None
return str
yolo_model = YOLO()
# for i in range(18,100):
# image_path = rf'Images/New/IMG_25{i}.jpeg' #95; 3909, 2491
# detect_license_plate(model=yolo_model, img_path=image_path, i=i)
image_path = rf'Images/Old/IMG_7823.jpeg' #95; 3909, 2491
detect_license_plate(model=yolo_model, img_path=image_path, i=0)
# print(ocr.get_text_from_image(f'img0.png'))
# print(ocr.keras_ocr_func())
# print(ocr.tesseract_ocr())