From 2a01241bf4f659054998e79bbbf01a62e39d384e Mon Sep 17 00:00:00 2001 From: dbqls200 Date: Fri, 29 Nov 2024 00:16:25 +0900 Subject: [PATCH 1/5] feat: #106 Add Share Extension to the project --- TMT/TMT.xcodeproj/project.pbxproj | 150 +++++++++++++++++- TMT/TMT/TMTRelease.entitlements | 10 ++ .../Base.lproj/MainInterface.storyboard | 24 +++ TMT/TMTShareExtension/Info.plist | 18 +++ .../ShareViewController.swift | 30 ++++ .../TMTShareExtensionRelease.entitlements | 10 ++ 6 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 TMT/TMT/TMTRelease.entitlements create mode 100644 TMT/TMTShareExtension/Base.lproj/MainInterface.storyboard create mode 100644 TMT/TMTShareExtension/Info.plist create mode 100644 TMT/TMTShareExtension/ShareViewController.swift create mode 100644 TMT/TMTShareExtension/TMTShareExtensionRelease.entitlements diff --git a/TMT/TMT.xcodeproj/project.pbxproj b/TMT/TMT.xcodeproj/project.pbxproj index 25de0f8..0588d60 100644 --- a/TMT/TMT.xcodeproj/project.pbxproj +++ b/TMT/TMT.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ 5BF33BF42CE70E2E006F17EC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D86739702CA933CE00FFE8ED /* Assets.xcassets */; }; 5BF33BF52CE70E37006F17EC /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D9E9B2CE47F12004F2024 /* Color.swift */; }; D801A1BA2CF2213C00AD0D64 /* BusDataMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D801A1B92CF2213C00AD0D64 /* BusDataMock.swift */; }; + D81238912CF8C0560005EB25 /* TMTShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D81238872CF8C0560005EB25 /* TMTShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D81D9D3C2CE21CD1004F2024 /* JourneySettingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D9D3B2CE21CD1004F2024 /* JourneySettingModel.swift */; }; D81D9E9A2CE47F0D004F2024 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D9E992CE47F0D004F2024 /* String.swift */; }; D81D9E9C2CE47F12004F2024 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D9E9B2CE47F12004F2024 /* Color.swift */; }; @@ -63,6 +64,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + D812388F2CF8C0560005EB25 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D86739612CA933CD00FFE8ED /* Project object */; + proxyType = 1; + remoteGlobalIDString = D81238862CF8C0560005EB25; + remoteInfo = TMTShareExtension; + }; D844BCCE2CC120030059E31F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D86739612CA933CD00FFE8ED /* Project object */; @@ -79,6 +87,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( + D81238912CF8C0560005EB25 /* TMTShareExtension.appex in Embed Foundation Extensions */, D844BCD02CC120030059E31F /* TMTWidgetExtension.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; @@ -111,6 +120,8 @@ 5BD0A4112CD67BC300AE88BF /* ScannedJourneyInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannedJourneyInfoView.swift; sourceTree = ""; }; D801A1B92CF2213C00AD0D64 /* BusDataMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BusDataMock.swift; sourceTree = ""; }; D803DE332CD8A80C00C36D17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + D81238872CF8C0560005EB25 /* TMTShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TMTShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + D81238962CF8C07C0005EB25 /* TMTRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TMTRelease.entitlements; sourceTree = ""; }; D81D9D3B2CE21CD1004F2024 /* JourneySettingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JourneySettingModel.swift; sourceTree = ""; }; D81D9E992CE47F0D004F2024 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; D81D9E9B2CE47F12004F2024 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; @@ -140,6 +151,13 @@ /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + D81238952CF8C0560005EB25 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = D81238862CF8C0560005EB25 /* TMTShareExtension */; + }; D844BCD12CC120030059E31F /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( @@ -157,10 +175,18 @@ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ + D81238882CF8C0560005EB25 /* TMTShareExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D81238952CF8C0560005EB25 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = TMTShareExtension; sourceTree = ""; }; D844BCC02CC120010059E31F /* TMTWidget */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D844BCD72CC120E40059E31F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, D844BCD12CC120030059E31F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = TMTWidget; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ + D81238842CF8C0560005EB25 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D844BCB72CC120010059E31F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -342,6 +368,7 @@ children = ( D867396B2CA933CD00FFE8ED /* TMT */, D844BCC02CC120010059E31F /* TMTWidget */, + D81238882CF8C0560005EB25 /* TMTShareExtension */, D844BCBB2CC120010059E31F /* Frameworks */, D867396A2CA933CD00FFE8ED /* Products */, ); @@ -352,6 +379,7 @@ children = ( D86739692CA933CD00FFE8ED /* TMT.app */, D844BCBA2CC120010059E31F /* TMTWidgetExtension.appex */, + D81238872CF8C0560005EB25 /* TMTShareExtension.appex */, ); name = Products; sourceTree = ""; @@ -359,6 +387,7 @@ D867396B2CA933CD00FFE8ED /* TMT */ = { isa = PBXGroup; children = ( + D81238962CF8C07C0005EB25 /* TMTRelease.entitlements */, D803DE332CD8A80C00C36D17 /* Info.plist */, D867396C2CA933CD00FFE8ED /* TMTApp.swift */, 5B347FCF2CF4F71F00A1E852 /* AppDelegate.swift */, @@ -434,6 +463,28 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + D81238862CF8C0560005EB25 /* TMTShareExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = D81238942CF8C0560005EB25 /* Build configuration list for PBXNativeTarget "TMTShareExtension" */; + buildPhases = ( + D81238832CF8C0560005EB25 /* Sources */, + D81238842CF8C0560005EB25 /* Frameworks */, + D81238852CF8C0560005EB25 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + D81238882CF8C0560005EB25 /* TMTShareExtension */, + ); + name = TMTShareExtension; + packageProductDependencies = ( + ); + productName = TMTShareExtension; + productReference = D81238872CF8C0560005EB25 /* TMTShareExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; D844BCB92CC120010059E31F /* TMTWidgetExtension */ = { isa = PBXNativeTarget; buildConfigurationList = D844BCD22CC120030059E31F /* Build configuration list for PBXNativeTarget "TMTWidgetExtension" */; @@ -469,6 +520,7 @@ ); dependencies = ( D844BCCF2CC120030059E31F /* PBXTargetDependency */, + D81238902CF8C0560005EB25 /* PBXTargetDependency */, ); name = TMT; productName = TMT; @@ -485,6 +537,9 @@ LastSwiftUpdateCheck = 1600; LastUpgradeCheck = 1600; TargetAttributes = { + D81238862CF8C0560005EB25 = { + CreatedOnToolsVersion = 16.0; + }; D844BCB92CC120010059E31F = { CreatedOnToolsVersion = 16.0; }; @@ -511,11 +566,19 @@ targets = ( D86739682CA933CD00FFE8ED /* TMT */, D844BCB92CC120010059E31F /* TMTWidgetExtension */, + D81238862CF8C0560005EB25 /* TMTShareExtension */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + D81238852CF8C0560005EB25 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D844BCB82CC120010059E31F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -541,6 +604,13 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + D81238832CF8C0560005EB25 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D844BCB62CC120010059E31F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -601,6 +671,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + D81238902CF8C0560005EB25 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D81238862CF8C0560005EB25 /* TMTShareExtension */; + targetProxy = D812388F2CF8C0560005EB25 /* PBXContainerItemProxy */; + }; D844BCCF2CC120030059E31F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D844BCB92CC120010059E31F /* TMTWidgetExtension */; @@ -609,13 +684,70 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + D81238922CF8C0560005EB25 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = TMTShareExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = TMTShareExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = twomanythinking.TMT.TMTShareExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + D81238932CF8C0560005EB25 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = TMTShareExtension/TMTShareExtensionRelease.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = TMTShareExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = TMTShareExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = twomanythinking.TMT.TMTShareExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; D844BCD32CC120030059E31F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; @@ -651,7 +783,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; @@ -806,7 +938,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"TMT/Preview Content\""; DEVELOPMENT_TEAM = ""; @@ -846,8 +978,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = TMT/TMTRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"TMT/Preview Content\""; DEVELOPMENT_TEAM = ""; @@ -885,6 +1018,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + D81238942CF8C0560005EB25 /* Build configuration list for PBXNativeTarget "TMTShareExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D81238922CF8C0560005EB25 /* Debug */, + D81238932CF8C0560005EB25 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; D844BCD22CC120030059E31F /* Build configuration list for PBXNativeTarget "TMTWidgetExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/TMT/TMT/TMTRelease.entitlements b/TMT/TMT/TMTRelease.entitlements new file mode 100644 index 0000000..ec6582e --- /dev/null +++ b/TMT/TMT/TMTRelease.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.twomanythinking.TMT + + + diff --git a/TMT/TMTShareExtension/Base.lproj/MainInterface.storyboard b/TMT/TMTShareExtension/Base.lproj/MainInterface.storyboard new file mode 100644 index 0000000..286a508 --- /dev/null +++ b/TMT/TMTShareExtension/Base.lproj/MainInterface.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TMT/TMTShareExtension/Info.plist b/TMT/TMTShareExtension/Info.plist new file mode 100644 index 0000000..4b1f7e7 --- /dev/null +++ b/TMT/TMTShareExtension/Info.plist @@ -0,0 +1,18 @@ + + + + + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + TRUEPREDICATE + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.share-services + + + diff --git a/TMT/TMTShareExtension/ShareViewController.swift b/TMT/TMTShareExtension/ShareViewController.swift new file mode 100644 index 0000000..80ebea5 --- /dev/null +++ b/TMT/TMTShareExtension/ShareViewController.swift @@ -0,0 +1,30 @@ +// +// ShareViewController.swift +// TMTShareExtension +// +// Created by 김유빈 on 11/29/24. +// + +import UIKit +import Social + +class ShareViewController: SLComposeServiceViewController { + + override func isContentValid() -> Bool { + // Do validation of contentText and/or NSExtensionContext attachments here + return true + } + + override func didSelectPost() { + // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. + + // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context. + self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) + } + + override func configurationItems() -> [Any]! { + // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here. + return [] + } + +} diff --git a/TMT/TMTShareExtension/TMTShareExtensionRelease.entitlements b/TMT/TMTShareExtension/TMTShareExtensionRelease.entitlements new file mode 100644 index 0000000..ec6582e --- /dev/null +++ b/TMT/TMTShareExtension/TMTShareExtensionRelease.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.twomanythinking.TMT + + + From 4102ac96c48136bc1f65524cf939dbf41b6127fa Mon Sep 17 00:00:00 2001 From: dbqls200 Date: Fri, 29 Nov 2024 00:20:03 +0900 Subject: [PATCH 2/5] feat: #106 Update Info.plist to allow photo sharing via Share Extension --- TMT/TMTShareExtension/Info.plist | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/TMT/TMTShareExtension/Info.plist b/TMT/TMTShareExtension/Info.plist index 4b1f7e7..8c033a2 100644 --- a/TMT/TMTShareExtension/Info.plist +++ b/TMT/TMTShareExtension/Info.plist @@ -7,7 +7,10 @@ NSExtensionAttributes NSExtensionActivationRule - TRUEPREDICATE + + NSExtensionActivationSupportsImageWithMaxCount + 1 + NSExtensionMainStoryboard MainInterface From 996c7f410148f216ae04ff877e99d682a4425a6f Mon Sep 17 00:00:00 2001 From: dbqls200 Date: Fri, 29 Nov 2024 00:22:11 +0900 Subject: [PATCH 3/5] chore: #106 Add UIImage handling function to image processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - loadImage 함수가 매개변수 타입에 따라, (PhotosPickerItem / UIImage)로 중복되어 있음. - PhotosPickerItem을 UIImage로 변환하는 함수 추가 예정 - loadImage 함수 하나로 두 타입 대응할 수 있도록 수정 예정 --- .../Models/ImageHandlerModel.swift | 37 +++++++++++++++++-- .../Views/NotUploadedView.swift | 2 +- .../Views/ScannedJourneyInfoView.swift | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/TMT/TMT/BusJourneyScanned/Models/ImageHandlerModel.swift b/TMT/TMT/BusJourneyScanned/Models/ImageHandlerModel.swift index 266cf7f..9a03f76 100644 --- a/TMT/TMT/BusJourneyScanned/Models/ImageHandlerModel.swift +++ b/TMT/TMT/BusJourneyScanned/Models/ImageHandlerModel.swift @@ -1,5 +1,5 @@ // -// ImageHandlerMode;.swift +// ImageHandlerModel.swift // TMT // // Created by Choi Minkyeong on 11/14/24. @@ -14,11 +14,11 @@ final class ImageHandlerModel: ObservableObject { @Published var showAlertText: Bool = false @Published var selectedImage: UIImage? = nil @Published var scannedJourneyInfo = ScannedJourneyInfo(busNumber: "", startStop: "", endStop: "") - + let ocrStarter = OCRStarterManager() - + /// 이미지를 로드하고 OCR을 진행하여 필요한 값을 뽑아냅니다. - func loadImage(from item: PhotosPickerItem?, viewCategory: String, completion: @escaping () -> Void) { + func loadImageByPhotosPickerItem(from item: PhotosPickerItem?, viewCategory: String, completion: @escaping () -> Void) { Task { guard let item = item else { return } if let data = try? await item.loadTransferable(type: Data.self), @@ -40,6 +40,7 @@ final class ImageHandlerModel: ObservableObject { } else { self.scannedJourneyInfo = self.ocrStarter.splitScannedInfo(scannedJourneyInfo: info) } + completion() } } else { @@ -47,4 +48,32 @@ final class ImageHandlerModel: ObservableObject { } } } + + func loadImagebyUIImage(from image: UIImage?, viewCategory: String, completion: @escaping () -> Void) { + guard let image = image else { return } + + Task { + DispatchQueue.main.async { + self.selectedImage = image + self.isLoading = true + self.showAlertScreen = false + self.showAlertText = false + } + + ocrStarter.startOCR(image: image) { info in + self.isLoading = false + + if info.busNumber.isEmpty && info.startStop.isEmpty && info.endStop.isEmpty { + if viewCategory == "NotUploadedView" { + self.showAlertScreen = true + } else if viewCategory == "ScannedJourneyInfoView" { + self.showAlertText = true + } + } else { + self.scannedJourneyInfo = self.ocrStarter.splitScannedInfo(scannedJourneyInfo: info) + } + completion() + } + } + } } diff --git a/TMT/TMT/BusJourneyScanned/Views/NotUploadedView.swift b/TMT/TMT/BusJourneyScanned/Views/NotUploadedView.swift index 3c1431a..e328e00 100644 --- a/TMT/TMT/BusJourneyScanned/Views/NotUploadedView.swift +++ b/TMT/TMT/BusJourneyScanned/Views/NotUploadedView.swift @@ -52,7 +52,7 @@ struct NotUploadedView: View { } } .onChange(of: pickedItem) { - imageHandler.loadImage(from: pickedItem, viewCategory: "NotUploadedView") { + imageHandler.loadImageByPhotosPickerItem(from: pickedItem, viewCategory: "NotUploadedView") { if !imageHandler.showAlertScreen { tag = 1 path.append("ScannedJourneyInfo") diff --git a/TMT/TMT/BusJourneyScanned/Views/ScannedJourneyInfoView.swift b/TMT/TMT/BusJourneyScanned/Views/ScannedJourneyInfoView.swift index 626203e..0f23f24 100644 --- a/TMT/TMT/BusJourneyScanned/Views/ScannedJourneyInfoView.swift +++ b/TMT/TMT/BusJourneyScanned/Views/ScannedJourneyInfoView.swift @@ -111,7 +111,7 @@ struct ScannedJourneyInfoView: View { EmptyView() } .onChange(of: pickedItem) { - imageHandler.loadImage(from: pickedItem, viewCategory: "ScannedJourneyInfoView", completion: {}) + imageHandler.loadImageByPhotosPickerItem(from: pickedItem, viewCategory: "ScannedJourneyInfoView", completion: {}) } .photosPicker(isPresented: $showingPhotosPicker, selection: $pickedItem, matching: .screenshots) From 1695c04085ee8d66c6bee29731f7e3270f264ef8 Mon Sep 17 00:00:00 2001 From: dbqls200 Date: Fri, 29 Nov 2024 00:37:02 +0900 Subject: [PATCH 4/5] feat: #106 Implement logic to share photo to app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사진 공유 sheet에 앱 노출 - 외부에서 앱으로 사진 공유하면 UserDefault에 저장 - UserDefault에 저장된 사진 가져와서 경로 설정 --- TMT/TMT.xcodeproj/project.pbxproj | 4 ++ .../Views/NotUploadedView.swift | 24 +++++-- .../Views/ScannedJourneyInfoView.swift | 10 +-- TMT/TMT/TMT.entitlements | 10 +++ .../ShareViewController.swift | 68 +++++++++++++++---- .../TMTShareExtension.entitlements | 10 +++ 6 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 TMT/TMT/TMT.entitlements create mode 100644 TMT/TMTShareExtension/TMTShareExtension.entitlements diff --git a/TMT/TMT.xcodeproj/project.pbxproj b/TMT/TMT.xcodeproj/project.pbxproj index 0588d60..ba2ae33 100644 --- a/TMT/TMT.xcodeproj/project.pbxproj +++ b/TMT/TMT.xcodeproj/project.pbxproj @@ -122,6 +122,7 @@ D803DE332CD8A80C00C36D17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; D81238872CF8C0560005EB25 /* TMTShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TMTShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; D81238962CF8C07C0005EB25 /* TMTRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TMTRelease.entitlements; sourceTree = ""; }; + D81238982CF8C3380005EB25 /* TMT.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TMT.entitlements; sourceTree = ""; }; D81D9D3B2CE21CD1004F2024 /* JourneySettingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JourneySettingModel.swift; sourceTree = ""; }; D81D9E992CE47F0D004F2024 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; D81D9E9B2CE47F12004F2024 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; @@ -387,6 +388,7 @@ D867396B2CA933CD00FFE8ED /* TMT */ = { isa = PBXGroup; children = ( + D81238982CF8C3380005EB25 /* TMT.entitlements */, D81238962CF8C07C0005EB25 /* TMTRelease.entitlements */, D803DE332CD8A80C00C36D17 /* Info.plist */, D867396C2CA933CD00FFE8ED /* TMTApp.swift */, @@ -687,6 +689,7 @@ D81238922CF8C0560005EB25 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_ENTITLEMENTS = TMTShareExtension/TMTShareExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -937,6 +940,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = TMT/TMT.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; diff --git a/TMT/TMT/BusJourneyScanned/Views/NotUploadedView.swift b/TMT/TMT/BusJourneyScanned/Views/NotUploadedView.swift index e328e00..da369a2 100644 --- a/TMT/TMT/BusJourneyScanned/Views/NotUploadedView.swift +++ b/TMT/TMT/BusJourneyScanned/Views/NotUploadedView.swift @@ -14,7 +14,7 @@ struct NotUploadedView: View { @State private var showingAlert = false @State private var tag: Int? = nil @Binding var path: [String] - + var body: some View { ZStack { VStack { @@ -30,11 +30,11 @@ struct NotUploadedView: View { .multilineTextAlignment(.leading) Spacer() } - + NavigationLink(destination: ScannedJourneyInfoView(scannedJourneyInfo: $imageHandler.scannedJourneyInfo, path: $path).environmentObject(imageHandler), tag: 1, selection: $tag) { EmptyView() } - + PhotosPicker( selection: $pickedItem, matching: .screenshots @@ -70,10 +70,26 @@ struct NotUploadedView: View { Text("Image recognition failed during upload. Please upload the image again.") } } - + if imageHandler.isLoading { ProgressView() } } + .onAppear { + if let sharedDefaults = UserDefaults(suiteName: "group.twomanythinking.TMT"), + sharedDefaults.bool(forKey: "isShared"), + let imageData = sharedDefaults.data(forKey: "sharedImage"), + let image = UIImage(data: imageData) { + imageHandler.loadImagebyUIImage(from: image, viewCategory: "NotUploadedView") { + if !imageHandler.showAlertScreen { + tag = 1 + path.append("ScannedJourneyInfo") + } + + sharedDefaults.set(false, forKey: "isShared") + sharedDefaults.synchronize() + } + } + } } } diff --git a/TMT/TMT/BusJourneyScanned/Views/ScannedJourneyInfoView.swift b/TMT/TMT/BusJourneyScanned/Views/ScannedJourneyInfoView.swift index 0f23f24..7234b75 100644 --- a/TMT/TMT/BusJourneyScanned/Views/ScannedJourneyInfoView.swift +++ b/TMT/TMT/BusJourneyScanned/Views/ScannedJourneyInfoView.swift @@ -14,19 +14,19 @@ struct ScannedJourneyInfoView: View { @StateObject private var journeyModel: JourneySettingModel @StateObject private var activityManager: LiveActivityManager @StateObject var locationManager: LocationManager - + @State private var tag: Int? = nil @State private var showingAlert: Bool = false @State private var showingPhotosPicker: Bool = false @State private var isShowingInformation = false @State private var pickedItem: PhotosPickerItem? = nil @Binding var path: [String] - + init(scannedJourneyInfo: Binding, path: Binding<[String]>) { let searchModel = BusSearchModel() let journeyModel = JourneySettingModel(searchModel: searchModel) let activityManager = LiveActivityManager() - + _searchModel = StateObject(wrappedValue: searchModel) _journeyModel = StateObject(wrappedValue: journeyModel) _activityManager = StateObject(wrappedValue: activityManager) @@ -167,9 +167,9 @@ struct ScannedJourneyInfoView: View { } .disabled(isShowingInformation) } - + } - + private func uploadedInfoBox(title: String, scannedInfo: Binding) -> some View { VStack(alignment: .leading) { Text("\(title)") diff --git a/TMT/TMT/TMT.entitlements b/TMT/TMT/TMT.entitlements new file mode 100644 index 0000000..ec6582e --- /dev/null +++ b/TMT/TMT/TMT.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.twomanythinking.TMT + + + diff --git a/TMT/TMTShareExtension/ShareViewController.swift b/TMT/TMTShareExtension/ShareViewController.swift index 80ebea5..247d64c 100644 --- a/TMT/TMTShareExtension/ShareViewController.swift +++ b/TMT/TMTShareExtension/ShareViewController.swift @@ -2,29 +2,73 @@ // ShareViewController.swift // TMTShareExtension // -// Created by 김유빈 on 11/29/24. +// Created by 김유빈 on 11/22/24. // import UIKit import Social class ShareViewController: SLComposeServiceViewController { + override func viewDidLoad() { + super.viewDidLoad() + handleSharedImage() + } + + private func handleSharedImage() { + guard let inputItem = self.extensionContext?.inputItems.first as? NSExtensionItem, + let attachment = inputItem.attachments?.first, + attachment.hasItemConformingToTypeIdentifier("public.image") else { + return + } + + + attachment.loadItem(forTypeIdentifier: "public.image", options: nil) { item, error in + if let error = error { + self.completeExtensionAndOpenApp() + return + } - override func isContentValid() -> Bool { - // Do validation of contentText and/or NSExtensionContext attachments here - return true + if let url = item as? URL { // URL로 처리 + self.handleImageFromURL(url) + } else if let data = item as? Data, let image = UIImage(data: data) { // Data로 처리 + self.saveImageToApp(image) + } else { + self.completeExtensionAndOpenApp() + } + } } - override func didSelectPost() { - // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments. - - // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context. - self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) + private func handleImageFromURL(_ url: URL) { + // URL에서 이미지를 로드 + do { + let imageData = try Data(contentsOf: url) + if let image = UIImage(data: imageData) { + self.saveImageToApp(image) + } else { + self.completeExtensionAndOpenApp() + } + } catch { + self.completeExtensionAndOpenApp() + } } - override func configurationItems() -> [Any]! { - // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here. - return [] + private func saveImageToApp(_ image: UIImage) { + if let imageData = image.jpegData(compressionQuality: 1.0), + let sharedDefaults = UserDefaults(suiteName: "group.twomanythinking.TMT") { + sharedDefaults.set(imageData, forKey: "sharedImage") + sharedDefaults.set(true, forKey: "isShared") + sharedDefaults.synchronize() + } else { + } + + self.completeExtensionAndOpenApp() } + + private func completeExtensionAndOpenApp() { + // TODO: 앱으로 이동하기 + + // extension 종료 + self.extensionContext?.completeRequest(returningItems: nil) + } } diff --git a/TMT/TMTShareExtension/TMTShareExtension.entitlements b/TMT/TMTShareExtension/TMTShareExtension.entitlements new file mode 100644 index 0000000..ec6582e --- /dev/null +++ b/TMT/TMTShareExtension/TMTShareExtension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.twomanythinking.TMT + + + From ae75d099b87207eca2d5656a2715e25e7ab9b6ad Mon Sep 17 00:00:00 2001 From: dbqls200 Date: Fri, 29 Nov 2024 01:16:42 +0900 Subject: [PATCH 5/5] chore: #106 Add missing referenced files and include them in target membership --- TMT/TMT.xcodeproj/project.pbxproj | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/TMT/TMT.xcodeproj/project.pbxproj b/TMT/TMT.xcodeproj/project.pbxproj index ba2ae33..cd12bb4 100644 --- a/TMT/TMT.xcodeproj/project.pbxproj +++ b/TMT/TMT.xcodeproj/project.pbxproj @@ -15,7 +15,6 @@ 5B347FD02CF4F72400A1E852 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B347FCF2CF4F71F00A1E852 /* AppDelegate.swift */; }; 5B4F87342CC973F4000329C2 /* MapViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4F87332CC973F3000329C2 /* MapViewWrapper.swift */; }; 5B50F1872CE5D19100E2EC41 /* ImageHandlerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B50F1862CE5D14F00E2EC41 /* ImageHandlerModel.swift */; }; - 5B50F1892CE64EBE00E2EC41 /* ScannedJourneyInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B50F1882CE64EB500E2EC41 /* ScannedJourneyInfo.swift */; }; 5B64AF952CCF823D0083CA23 /* BusInfoEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B64AF942CCF82270083CA23 /* BusInfoEnum.swift */; }; 5B6DA5B82CBE551400613ACB /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6DA5B72CBE551400613ACB /* MapView.swift */; }; 5B6DA5BA2CBE6F8C00613ACB /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6DA5B92CBE6F8700613ACB /* LocationManager.swift */; }; @@ -25,14 +24,15 @@ 5BA06D4A2CF38E5400834BBD /* TappedStopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA06D492CF38E1F00834BBD /* TappedStopView.swift */; }; 5BA06D4C2CF3A63000834BBD /* PopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA06D4B2CF3A61C00834BBD /* PopoverView.swift */; }; 5BA3A5852CE12D8900C2DEA0 /* BusStopData.csv in Resources */ = {isa = PBXBuildFile; fileRef = 5BA3A5842CE12D8900C2DEA0 /* BusStopData.csv */; }; - 5BE1BF082CF867590082648D /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BE1BF072CF867550082648D /* NotificationManager.swift */; }; - 5BB6D2582CD3DD1100F6A487 /* EndStopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB6D2572CD3DD0D00F6A487 /* EndStopView.swift */; }; 5BCC7CC82CF5BEDB005986BF /* BusStopDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BCC7CC72CF5BED4005986BF /* BusStopDetailView.swift */; }; - 5BD0A4122CD67BD400AE88BF /* ScannedJourneyInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD0A4112CD67BC300AE88BF /* ScannedJourneyInfoView.swift */; }; + 5BE1BF082CF867590082648D /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BE1BF072CF867550082648D /* NotificationManager.swift */; }; 5BF33BF42CE70E2E006F17EC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D86739702CA933CE00FFE8ED /* Assets.xcassets */; }; 5BF33BF52CE70E37006F17EC /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D9E9B2CE47F12004F2024 /* Color.swift */; }; D801A1BA2CF2213C00AD0D64 /* BusDataMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D801A1B92CF2213C00AD0D64 /* BusDataMock.swift */; }; D81238912CF8C0560005EB25 /* TMTShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D81238872CF8C0560005EB25 /* TMTShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + D81238C82CF8CD760005EB25 /* ScannedJourneyInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81238C72CF8CD760005EB25 /* ScannedJourneyInfoView.swift */; }; + D81238C92CF8CD920005EB25 /* ScannedJourneyInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B50F1882CE64EB500E2EC41 /* ScannedJourneyInfo.swift */; }; + D81238CA2CF8CDAE0005EB25 /* EndStopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB6D2572CD3DD0D00F6A487 /* EndStopView.swift */; }; D81D9D3C2CE21CD1004F2024 /* JourneySettingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D9D3B2CE21CD1004F2024 /* JourneySettingModel.swift */; }; D81D9E9A2CE47F0D004F2024 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D9E992CE47F0D004F2024 /* String.swift */; }; D81D9E9C2CE47F12004F2024 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D9E9B2CE47F12004F2024 /* Color.swift */; }; @@ -114,15 +114,15 @@ 5BA06D492CF38E1F00834BBD /* TappedStopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TappedStopView.swift; sourceTree = ""; }; 5BA06D4B2CF3A61C00834BBD /* PopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopoverView.swift; sourceTree = ""; }; 5BA3A5842CE12D8900C2DEA0 /* BusStopData.csv */ = {isa = PBXFileReference; lastKnownFileType = text; path = BusStopData.csv; sourceTree = ""; }; - 5BE1BF072CF867550082648D /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = ""; }; 5BB6D2572CD3DD0D00F6A487 /* EndStopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndStopView.swift; sourceTree = ""; }; 5BCC7CC72CF5BED4005986BF /* BusStopDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BusStopDetailView.swift; sourceTree = ""; }; - 5BD0A4112CD67BC300AE88BF /* ScannedJourneyInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannedJourneyInfoView.swift; sourceTree = ""; }; + 5BE1BF072CF867550082648D /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = ""; }; D801A1B92CF2213C00AD0D64 /* BusDataMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BusDataMock.swift; sourceTree = ""; }; D803DE332CD8A80C00C36D17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; D81238872CF8C0560005EB25 /* TMTShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TMTShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; D81238962CF8C07C0005EB25 /* TMTRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TMTRelease.entitlements; sourceTree = ""; }; D81238982CF8C3380005EB25 /* TMT.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TMT.entitlements; sourceTree = ""; }; + D81238C72CF8CD760005EB25 /* ScannedJourneyInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannedJourneyInfoView.swift; sourceTree = ""; }; D81D9D3B2CE21CD1004F2024 /* JourneySettingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JourneySettingModel.swift; sourceTree = ""; }; D81D9E992CE47F0D004F2024 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; D81D9E9B2CE47F12004F2024 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; @@ -282,8 +282,8 @@ D81D9E942CE47E01004F2024 /* Views */ = { isa = PBXGroup; children = ( + D81238C72CF8CD760005EB25 /* ScannedJourneyInfoView.swift */, 5B83D51D2CD7D80900633B3C /* NotUploadedView.swift */, - 5BCC7CEF2CF5FF93005986BF /* ScannedJourneyInfoView.swift */, 5B04FC502CD9BBFD00163877 /* UploadedPhotoView.swift */, ); path = Views; @@ -313,7 +313,6 @@ D81D9E972CE47E82004F2024 /* Views */ = { isa = PBXGroup; children = ( - 5BE1BF052CF864C30082648D /* BusStopDetailView.swift */, 5B347FCD2CF49DBC00A1E852 /* BusStopArrivalView.swift */, 5BA06D4B2CF3A61C00834BBD /* PopoverView.swift */, 5BA06D492CF38E1F00834BBD /* TappedStopView.swift */, @@ -618,7 +617,6 @@ buildActionMask = 2147483647; files = ( D8E7E7122CF60FD300EAD54F /* StopStatusEnum.swift in Sources */, - 5BE1BF092CF867590082648D /* NotificationManager.swift in Sources */, D8E054DD2CF1AF89006B1879 /* View.swift in Sources */, 5BF33BF52CE70E37006F17EC /* Color.swift in Sources */, ); @@ -630,13 +628,11 @@ files = ( 5BCC7CC82CF5BEDB005986BF /* BusStopDetailView.swift in Sources */, D83277652CEC67CE005E00CF /* LottieView.swift in Sources */, - 5BCC7D162CF601E1005986BF /* EndStopView.swift in Sources */, D8D377E92CBE95C30043D103 /* BusSearchItem.swift in Sources */, - 5BE1BF062CF864CB0082648D /* BusStopDetailView.swift in Sources */, 5B04FC512CD9BC0400163877 /* UploadedPhotoView.swift in Sources */, 5B2D9A122CCA1553001FF6CC /* OCRStarterManager.swift in Sources */, - 5BCC7CF02CF5FF93005986BF /* ScannedJourneyInfoView.swift in Sources */, 5B2D9A122CCA1553001FF6CC /* OCRStarterManager.swift in Sources */, + D81238C82CF8CD760005EB25 /* ScannedJourneyInfoView.swift in Sources */, 5B50F1872CE5D19100E2EC41 /* ImageHandlerModel.swift in Sources */, 5B85B1C22CD91CC000469D03 /* HomeView.swift in Sources */, 5B0C4AF42CD52E1800031147 /* StopStatusEnum.swift in Sources */, @@ -649,6 +645,7 @@ D826488F2CD35550000A448D /* ButtonComponent.swift in Sources */, D867396D2CA933CD00FFE8ED /* TMTApp.swift in Sources */, 5B4F87342CC973F4000329C2 /* MapViewWrapper.swift in Sources */, + D81238CA2CF8CDAE0005EB25 /* EndStopView.swift in Sources */, D8D377EB2CBE95CA0043D103 /* BusSearchModel.swift in Sources */, 5BE1BF082CF867590082648D /* NotificationManager.swift in Sources */, D801A1BA2CF2213C00AD0D64 /* BusDataMock.swift in Sources */, @@ -662,6 +659,7 @@ D844BCDA2CC147390059E31F /* LiveActivityManager.swift in Sources */, 5B83D51E2CD7D81F00633B3C /* NotUploadedView.swift in Sources */, D858729C2CD4A15F001CC467 /* OnboardingStepView.swift in Sources */, + D81238C92CF8CD920005EB25 /* ScannedJourneyInfo.swift in Sources */, D88F3AF22CD34DD200C0B657 /* InformationModalView.swift in Sources */, D8E054DE2CF1AF89006B1879 /* View.swift in Sources */, D81D9D3C2CE21CD1004F2024 /* JourneySettingModel.swift in Sources */,