Merge pull request 'fix/auth/payment-login-lockout' (#44) from fix/auth/payment-login-lockout into main
Reviewed-on: Loverde-Company-LTDA/Pedi-Foods-Skip#44
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 56;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
2B202626C34FC9F5C87C0388 /* ApiOrderModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4625B70E3E8BEEB9D0B2042 /* ApiOrderModels.swift */; };
|
2B202626C34FC9F5C87C0388 /* ApiOrderModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4625B70E3E8BEEB9D0B2042 /* ApiOrderModels.swift */; };
|
||||||
2F56755488E951C453AC2126 /* LCEssentials in Frameworks */ = {isa = PBXBuildFile; productRef = B8D5E8821C95A331C3A19DA1 /* LCEssentials */; };
|
2F56755488E951C453AC2126 /* LCEssentials in Frameworks */ = {isa = PBXBuildFile; productRef = B8D5E8821C95A331C3A19DA1 /* LCEssentials */; };
|
||||||
2FCB3403A764AD74AC3BD47C /* LegalDocumentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AA914FB8B32B106911FD67B /* LegalDocumentTests.swift */; };
|
2FCB3403A764AD74AC3BD47C /* LegalDocumentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AA914FB8B32B106911FD67B /* LegalDocumentTests.swift */; };
|
||||||
|
901A6A5A00C18FC59F764B85 /* PublicStoreDistanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E55893DD92CBFB24F212454 /* PublicStoreDistanceTests.swift */; };
|
||||||
33AB0B87867400F3D0C65FA0 /* ApiClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DBC4B9B43C015C4DD411359 /* ApiClient.swift */; };
|
33AB0B87867400F3D0C65FA0 /* ApiClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DBC4B9B43C015C4DD411359 /* ApiClient.swift */; };
|
||||||
3689239282AADF06783CBBEA /* AuthFormatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B3C375FC18002A884A44F1 /* AuthFormatters.swift */; };
|
3689239282AADF06783CBBEA /* AuthFormatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B3C375FC18002A884A44F1 /* AuthFormatters.swift */; };
|
||||||
3BD69E880EBC797B87EE547B /* StoreDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71DB74B676A58B367F026090 /* StoreDetailView.swift */; };
|
3BD69E880EBC797B87EE547B /* StoreDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71DB74B676A58B367F026090 /* StoreDetailView.swift */; };
|
||||||
@@ -79,7 +80,7 @@
|
|||||||
7CC171B83BC4CDEC38B25F8C /* SnackbarCenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2CE116C585A7529CF309B3D /* SnackbarCenterTests.swift */; };
|
7CC171B83BC4CDEC38B25F8C /* SnackbarCenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2CE116C585A7529CF309B3D /* SnackbarCenterTests.swift */; };
|
||||||
7D7BF04765D6CA6AC4F11DDD /* StoreCatalogNormalizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EC38EEE1E7105BC21E354C /* StoreCatalogNormalizerTests.swift */; };
|
7D7BF04765D6CA6AC4F11DDD /* StoreCatalogNormalizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EC38EEE1E7105BC21E354C /* StoreCatalogNormalizerTests.swift */; };
|
||||||
80B476CCE2B90BEE2FA4CB37 /* PediFoodsUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E3E6C1834786CA3621B7BB /* PediFoodsUITestsLaunchTests.swift */; };
|
80B476CCE2B90BEE2FA4CB37 /* PediFoodsUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E3E6C1834786CA3621B7BB /* PediFoodsUITestsLaunchTests.swift */; };
|
||||||
811217F88AA350A70CC22479 /* NotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C724E02EC34BB1D4352C2FF0 /* NotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
811217F88AA350A70CC22479 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C724E02EC34BB1D4352C2FF0 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
85EA52253BABA327EC07CFF0 /* AuthFormattersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 561E00C486D60EC2DF720EAF /* AuthFormattersTests.swift */; };
|
85EA52253BABA327EC07CFF0 /* AuthFormattersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 561E00C486D60EC2DF720EAF /* AuthFormattersTests.swift */; };
|
||||||
8D6622AE9325D02B830BD115 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CAA9B253B1A6C8815A0E69D /* LaunchScreen.storyboard */; };
|
8D6622AE9325D02B830BD115 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CAA9B253B1A6C8815A0E69D /* LaunchScreen.storyboard */; };
|
||||||
90ADA376585F5438F3A1A1D6 /* HomeView+Favorites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517B141263438E466452037 /* HomeView+Favorites.swift */; };
|
90ADA376585F5438F3A1A1D6 /* HomeView+Favorites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517B141263438E466452037 /* HomeView+Favorites.swift */; };
|
||||||
@@ -114,7 +115,6 @@
|
|||||||
CCE23FD7706B34BDE544E05A /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EC381D02A37312BE360024F /* Buttons.swift */; };
|
CCE23FD7706B34BDE544E05A /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EC381D02A37312BE360024F /* Buttons.swift */; };
|
||||||
CD96980F3D7B603126FDE6AC /* URLProtocolStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51798A414469C911D44F0F6 /* URLProtocolStub.swift */; };
|
CD96980F3D7B603126FDE6AC /* URLProtocolStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51798A414469C911D44F0F6 /* URLProtocolStub.swift */; };
|
||||||
CEA08090E08B5E39FD0DD5D6 /* CachedRemoteImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECF1BBC608B65EC1F1B6114 /* CachedRemoteImage.swift */; };
|
CEA08090E08B5E39FD0DD5D6 /* CachedRemoteImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECF1BBC608B65EC1F1B6114 /* CachedRemoteImage.swift */; };
|
||||||
38452FD60CBDE248531DA484 /* AppBackButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EEF6262A813BB8274266C8 /* AppBackButtonIcon.swift */; };
|
|
||||||
D2FB3C624B3C27E59BCA997A /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EA34EE194C71755B3C82F30 /* MainTabView.swift */; };
|
D2FB3C624B3C27E59BCA997A /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EA34EE194C71755B3C82F30 /* MainTabView.swift */; };
|
||||||
D3EC6E0A68B809F7A3370B1B /* ProductDetailSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553A05B9EAD0B9D0D9F1B369 /* ProductDetailSheet.swift */; };
|
D3EC6E0A68B809F7A3370B1B /* ProductDetailSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553A05B9EAD0B9D0D9F1B369 /* ProductDetailSheet.swift */; };
|
||||||
D48148B155BA2F76C41C0787 /* HomeFiltersStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FBD7D809ACE1840165A9DCC /* HomeFiltersStateTests.swift */; };
|
D48148B155BA2F76C41C0787 /* HomeFiltersStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FBD7D809ACE1840165A9DCC /* HomeFiltersStateTests.swift */; };
|
||||||
@@ -128,6 +128,7 @@
|
|||||||
E4D492E4B651A8FCC5016B43 /* PizzaFlavorAddonsSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ECD3AA9543133BE623668D /* PizzaFlavorAddonsSheet.swift */; };
|
E4D492E4B651A8FCC5016B43 /* PizzaFlavorAddonsSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ECD3AA9543133BE623668D /* PizzaFlavorAddonsSheet.swift */; };
|
||||||
E7817C56D8F083A231E11E4E /* LocationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAB9F980426D39E93E091051 /* LocationService.swift */; };
|
E7817C56D8F083A231E11E4E /* LocationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAB9F980426D39E93E091051 /* LocationService.swift */; };
|
||||||
EBBF7EFFDC9286D4F64544F4 /* PublicLocationModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85F176EA2B204CC95072D28 /* PublicLocationModels.swift */; };
|
EBBF7EFFDC9286D4F64544F4 /* PublicLocationModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85F176EA2B204CC95072D28 /* PublicLocationModels.swift */; };
|
||||||
|
EC9F35551075A78EF7869784 /* AppBackButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3056B162576522D94702AE6E /* AppBackButtonIcon.swift */; };
|
||||||
ECFEB3B3779C4F267EC148A4 /* SnackbarCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 226D1B7C049B405436DD36B4 /* SnackbarCenter.swift */; };
|
ECFEB3B3779C4F267EC148A4 /* SnackbarCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 226D1B7C049B405436DD36B4 /* SnackbarCenter.swift */; };
|
||||||
F03F08F65DFAD9166884EAD4 /* StoreCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31916C1A4005396ADA5FF3BC /* StoreCard.swift */; };
|
F03F08F65DFAD9166884EAD4 /* StoreCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31916C1A4005396ADA5FF3BC /* StoreCard.swift */; };
|
||||||
F280C0AC9902B13E2224C790 /* OrdersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF413C3924669E761BF455B8 /* OrdersView.swift */; };
|
F280C0AC9902B13E2224C790 /* OrdersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF413C3924669E761BF455B8 /* OrdersView.swift */; };
|
||||||
@@ -168,7 +169,7 @@
|
|||||||
dstPath = "";
|
dstPath = "";
|
||||||
dstSubfolderSpec = 13;
|
dstSubfolderSpec = 13;
|
||||||
files = (
|
files = (
|
||||||
811217F88AA350A70CC22479 /* NotificationServiceExtension.appex in Embed Foundation Extensions */,
|
811217F88AA350A70CC22479 /* NotificationService.appex in Embed Foundation Extensions */,
|
||||||
);
|
);
|
||||||
name = "Embed Foundation Extensions";
|
name = "Embed Foundation Extensions";
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -199,6 +200,7 @@
|
|||||||
2EA34EE194C71755B3C82F30 /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = "<group>"; };
|
2EA34EE194C71755B3C82F30 /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = "<group>"; };
|
||||||
2F4ED1B7B71C905115380DC0 /* FeatureControlService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureControlService.swift; sourceTree = "<group>"; };
|
2F4ED1B7B71C905115380DC0 /* FeatureControlService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureControlService.swift; sourceTree = "<group>"; };
|
||||||
30024AC97E79912E1358DDFB /* FiltersModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersModalView.swift; sourceTree = "<group>"; };
|
30024AC97E79912E1358DDFB /* FiltersModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiltersModalView.swift; sourceTree = "<group>"; };
|
||||||
|
3056B162576522D94702AE6E /* AppBackButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppBackButtonIcon.swift; sourceTree = "<group>"; };
|
||||||
30B3B6E69309F3EDF28E81CC /* LegalViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalViews.swift; sourceTree = "<group>"; };
|
30B3B6E69309F3EDF28E81CC /* LegalViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalViews.swift; sourceTree = "<group>"; };
|
||||||
31916C1A4005396ADA5FF3BC /* StoreCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreCard.swift; sourceTree = "<group>"; };
|
31916C1A4005396ADA5FF3BC /* StoreCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreCard.swift; sourceTree = "<group>"; };
|
||||||
35400BEE3D09C61B2058579F /* AppContentCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentCacheTests.swift; sourceTree = "<group>"; };
|
35400BEE3D09C61B2058579F /* AppContentCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentCacheTests.swift; sourceTree = "<group>"; };
|
||||||
@@ -227,7 +229,7 @@
|
|||||||
69A9FB3DE679C3D4C60E7E42 /* ApiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiConfig.swift; sourceTree = "<group>"; };
|
69A9FB3DE679C3D4C60E7E42 /* ApiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiConfig.swift; sourceTree = "<group>"; };
|
||||||
6BF467DF1447525F04B242B0 /* ReviewsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewsView.swift; sourceTree = "<group>"; };
|
6BF467DF1447525F04B242B0 /* ReviewsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewsView.swift; sourceTree = "<group>"; };
|
||||||
6CAA9B253B1A6C8815A0E69D /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
6CAA9B253B1A6C8815A0E69D /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
6DD1D8390E57439A347F9E07 /* PediFoodsTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = PediFoodsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
6DD1D8390E57439A347F9E07 /* PediFoodsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PediFoodsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
6EC381D02A37312BE360024F /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
|
6EC381D02A37312BE360024F /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
|
||||||
6FC454261845C1EDF970552A /* CheckoutTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckoutTypes.swift; sourceTree = "<group>"; };
|
6FC454261845C1EDF970552A /* CheckoutTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckoutTypes.swift; sourceTree = "<group>"; };
|
||||||
7034E89267D9F5D86BF1E424 /* CartCheckoutFlowTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartCheckoutFlowTests.swift; sourceTree = "<group>"; };
|
7034E89267D9F5D86BF1E424 /* CartCheckoutFlowTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartCheckoutFlowTests.swift; sourceTree = "<group>"; };
|
||||||
@@ -240,7 +242,7 @@
|
|||||||
76B24E69A3F6A3EB86449870 /* AddAddressFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAddressFormView.swift; sourceTree = "<group>"; };
|
76B24E69A3F6A3EB86449870 /* AddAddressFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAddressFormView.swift; sourceTree = "<group>"; };
|
||||||
794249487F718BCFBF176E8D /* ApiModelsDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiModelsDecodingTests.swift; sourceTree = "<group>"; };
|
794249487F718BCFBF176E8D /* ApiModelsDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiModelsDecodingTests.swift; sourceTree = "<group>"; };
|
||||||
79D2854B8062D96742CFDD99 /* HomeViewComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewComponents.swift; sourceTree = "<group>"; };
|
79D2854B8062D96742CFDD99 /* HomeViewComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewComponents.swift; sourceTree = "<group>"; };
|
||||||
7A6D74FD2D2F2F79349EA04E /* PediFoods.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = PediFoods.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
7A6D74FD2D2F2F79349EA04E /* PediFoods.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PediFoods.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
7A9F14B1BDD7747C546DFAF0 /* GuestSessionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuestSessionService.swift; sourceTree = "<group>"; };
|
7A9F14B1BDD7747C546DFAF0 /* GuestSessionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuestSessionService.swift; sourceTree = "<group>"; };
|
||||||
7C13751F450A42A2BDB0783D /* ProfileLoggedOutFlowTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileLoggedOutFlowTests.swift; sourceTree = "<group>"; };
|
7C13751F450A42A2BDB0783D /* ProfileLoggedOutFlowTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileLoggedOutFlowTests.swift; sourceTree = "<group>"; };
|
||||||
7CD06F9A7AF9365D1FBE35D0 /* AddressComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressComponents.swift; sourceTree = "<group>"; };
|
7CD06F9A7AF9365D1FBE35D0 /* AddressComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressComponents.swift; sourceTree = "<group>"; };
|
||||||
@@ -249,7 +251,8 @@
|
|||||||
89B662E8B7E1B8F1CF7E657E /* KeychainStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStore.swift; sourceTree = "<group>"; };
|
89B662E8B7E1B8F1CF7E657E /* KeychainStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStore.swift; sourceTree = "<group>"; };
|
||||||
8A3FB85A2A2E2952B9A2BAB0 /* DeepLinkDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkDestination.swift; sourceTree = "<group>"; };
|
8A3FB85A2A2E2952B9A2BAB0 /* DeepLinkDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkDestination.swift; sourceTree = "<group>"; };
|
||||||
8AA914FB8B32B106911FD67B /* LegalDocumentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalDocumentTests.swift; sourceTree = "<group>"; };
|
8AA914FB8B32B106911FD67B /* LegalDocumentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalDocumentTests.swift; sourceTree = "<group>"; };
|
||||||
8AF987AB319512C123DFD558 /* PediFoodsUITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = PediFoodsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
4E55893DD92CBFB24F212454 /* PublicStoreDistanceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicStoreDistanceTests.swift; sourceTree = "<group>"; };
|
||||||
|
8AF987AB319512C123DFD558 /* PediFoodsUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PediFoodsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
8D2C6A0E85E133F947293181 /* OrderDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetailsView.swift; sourceTree = "<group>"; };
|
8D2C6A0E85E133F947293181 /* OrderDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetailsView.swift; sourceTree = "<group>"; };
|
||||||
8DD2B73D89E6D33643EF58F5 /* DeepLinkRouteEffectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkRouteEffectTests.swift; sourceTree = "<group>"; };
|
8DD2B73D89E6D33643EF58F5 /* DeepLinkRouteEffectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkRouteEffectTests.swift; sourceTree = "<group>"; };
|
||||||
8E3A0A2E253ABFCA35D02F28 /* TextFieldCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldCompat.swift; sourceTree = "<group>"; };
|
8E3A0A2E253ABFCA35D02F28 /* TextFieldCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldCompat.swift; sourceTree = "<group>"; };
|
||||||
@@ -284,7 +287,7 @@
|
|||||||
C44662BAA20AD862BE1DBC40 /* PublicLocationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicLocationService.swift; sourceTree = "<group>"; };
|
C44662BAA20AD862BE1DBC40 /* PublicLocationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicLocationService.swift; sourceTree = "<group>"; };
|
||||||
C4745C12F14B695C77DFE178 /* SnackbarOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarOverlay.swift; sourceTree = "<group>"; };
|
C4745C12F14B695C77DFE178 /* SnackbarOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarOverlay.swift; sourceTree = "<group>"; };
|
||||||
C6B08901A67C8D90A3B50882 /* ApiCustomerPayloadModelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiCustomerPayloadModelsTests.swift; sourceTree = "<group>"; };
|
C6B08901A67C8D90A3B50882 /* ApiCustomerPayloadModelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiCustomerPayloadModelsTests.swift; sourceTree = "<group>"; };
|
||||||
C724E02EC34BB1D4352C2FF0 /* NotificationServiceExtension.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = NotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
C724E02EC34BB1D4352C2FF0 /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
CA44F5384D21B7F718F95522 /* StoreDetailSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreDetailSupport.swift; sourceTree = "<group>"; };
|
CA44F5384D21B7F718F95522 /* StoreDetailSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreDetailSupport.swift; sourceTree = "<group>"; };
|
||||||
CAB9F980426D39E93E091051 /* LocationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationService.swift; sourceTree = "<group>"; };
|
CAB9F980426D39E93E091051 /* LocationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationService.swift; sourceTree = "<group>"; };
|
||||||
CD5EE81AE4347B4086684F8B /* CartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartView.swift; sourceTree = "<group>"; };
|
CD5EE81AE4347B4086684F8B /* CartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartView.swift; sourceTree = "<group>"; };
|
||||||
@@ -300,7 +303,6 @@
|
|||||||
EB95D6804877D2ED244811D0 /* Inputs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Inputs.swift; sourceTree = "<group>"; };
|
EB95D6804877D2ED244811D0 /* Inputs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Inputs.swift; sourceTree = "<group>"; };
|
||||||
ECBFCE20C54A79DEA8F4512B /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
|
ECBFCE20C54A79DEA8F4512B /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
|
||||||
EECF1BBC608B65EC1F1B6114 /* CachedRemoteImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedRemoteImage.swift; sourceTree = "<group>"; };
|
EECF1BBC608B65EC1F1B6114 /* CachedRemoteImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedRemoteImage.swift; sourceTree = "<group>"; };
|
||||||
52EEF6262A813BB8274266C8 /* AppBackButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppBackButtonIcon.swift; sourceTree = "<group>"; };
|
|
||||||
F0B079DFAB606DCA87A536C9 /* LaunchSplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchSplashView.swift; sourceTree = "<group>"; };
|
F0B079DFAB606DCA87A536C9 /* LaunchSplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchSplashView.swift; sourceTree = "<group>"; };
|
||||||
F18F768F7A2A47111A85FE88 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
F18F768F7A2A47111A85FE88 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
||||||
F2B2C5BBDFF4473C472F45B4 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
|
F2B2C5BBDFF4473C472F45B4 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
|
||||||
@@ -344,7 +346,7 @@
|
|||||||
126A579C448C784867DC3AB1 /* Products */ = {
|
126A579C448C784867DC3AB1 /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C724E02EC34BB1D4352C2FF0 /* NotificationServiceExtension.appex */,
|
C724E02EC34BB1D4352C2FF0 /* NotificationService.appex */,
|
||||||
7A6D74FD2D2F2F79349EA04E /* PediFoods.app */,
|
7A6D74FD2D2F2F79349EA04E /* PediFoods.app */,
|
||||||
6DD1D8390E57439A347F9E07 /* PediFoodsTests.xctest */,
|
6DD1D8390E57439A347F9E07 /* PediFoodsTests.xctest */,
|
||||||
8AF987AB319512C123DFD558 /* PediFoodsUITests.xctest */,
|
8AF987AB319512C123DFD558 /* PediFoodsUITests.xctest */,
|
||||||
@@ -446,6 +448,7 @@
|
|||||||
23B6B814027518969EB04341 /* HomeViewFilteringTests.swift */,
|
23B6B814027518969EB04341 /* HomeViewFilteringTests.swift */,
|
||||||
5A82497C63D507E82FE02693 /* ImageSourceResolverTests.swift */,
|
5A82497C63D507E82FE02693 /* ImageSourceResolverTests.swift */,
|
||||||
8AA914FB8B32B106911FD67B /* LegalDocumentTests.swift */,
|
8AA914FB8B32B106911FD67B /* LegalDocumentTests.swift */,
|
||||||
|
4E55893DD92CBFB24F212454 /* PublicStoreDistanceTests.swift */,
|
||||||
747AD255B6D881E011FDF907 /* SessionStateStoreTests.swift */,
|
747AD255B6D881E011FDF907 /* SessionStateStoreTests.swift */,
|
||||||
160571AB2F8D4DF98C0BE16F /* SmokeTests.swift */,
|
160571AB2F8D4DF98C0BE16F /* SmokeTests.swift */,
|
||||||
B2CE116C585A7529CF309B3D /* SnackbarCenterTests.swift */,
|
B2CE116C585A7529CF309B3D /* SnackbarCenterTests.swift */,
|
||||||
@@ -558,9 +561,9 @@
|
|||||||
D7552D3AF029ADAC7DE5A76B /* Components */ = {
|
D7552D3AF029ADAC7DE5A76B /* Components */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
3056B162576522D94702AE6E /* AppBackButtonIcon.swift */,
|
||||||
6EC381D02A37312BE360024F /* Buttons.swift */,
|
6EC381D02A37312BE360024F /* Buttons.swift */,
|
||||||
EECF1BBC608B65EC1F1B6114 /* CachedRemoteImage.swift */,
|
EECF1BBC608B65EC1F1B6114 /* CachedRemoteImage.swift */,
|
||||||
52EEF6262A813BB8274266C8 /* AppBackButtonIcon.swift */,
|
|
||||||
EB95D6804877D2ED244811D0 /* Inputs.swift */,
|
EB95D6804877D2ED244811D0 /* Inputs.swift */,
|
||||||
C4745C12F14B695C77DFE178 /* SnackbarOverlay.swift */,
|
C4745C12F14B695C77DFE178 /* SnackbarOverlay.swift */,
|
||||||
31916C1A4005396ADA5FF3BC /* StoreCard.swift */,
|
31916C1A4005396ADA5FF3BC /* StoreCard.swift */,
|
||||||
@@ -621,7 +624,7 @@
|
|||||||
);
|
);
|
||||||
name = NotificationServiceExtension;
|
name = NotificationServiceExtension;
|
||||||
productName = NotificationServiceExtension;
|
productName = NotificationServiceExtension;
|
||||||
productReference = C724E02EC34BB1D4352C2FF0 /* NotificationServiceExtension.appex */;
|
productReference = C724E02EC34BB1D4352C2FF0 /* NotificationService.appex */;
|
||||||
productType = "com.apple.product-type.app-extension";
|
productType = "com.apple.product-type.app-extension";
|
||||||
};
|
};
|
||||||
66486D25E3A8A75EA8FACE44 /* PediFoodsUITests */ = {
|
66486D25E3A8A75EA8FACE44 /* PediFoodsUITests */ = {
|
||||||
@@ -671,15 +674,10 @@
|
|||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
LastUpgradeCheck = 1430;
|
LastUpgradeCheck = 1430;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
33EB2407F0F758EB98A769D3 = {
|
|
||||||
DevelopmentTeam = K4E5BZMM4V;
|
|
||||||
ProvisioningStyle = Automatic;
|
|
||||||
};
|
|
||||||
66486D25E3A8A75EA8FACE44 = {
|
66486D25E3A8A75EA8FACE44 = {
|
||||||
TestTargetID = B3B5CFF77A8ED019D1299ABB;
|
TestTargetID = B3B5CFF77A8ED019D1299ABB;
|
||||||
};
|
};
|
||||||
B3B5CFF77A8ED019D1299ABB = {
|
B3B5CFF77A8ED019D1299ABB = {
|
||||||
ProvisioningStyle = Manual;
|
|
||||||
SystemCapabilities = {
|
SystemCapabilities = {
|
||||||
com.apple.Push = {
|
com.apple.Push = {
|
||||||
enabled = YES;
|
enabled = YES;
|
||||||
@@ -775,6 +773,7 @@
|
|||||||
42FD703A96353119FAB2F711 /* ApiPizzaModels.swift in Sources */,
|
42FD703A96353119FAB2F711 /* ApiPizzaModels.swift in Sources */,
|
||||||
691351CFE207B9F34361AEB6 /* ApiReviewModels.swift in Sources */,
|
691351CFE207B9F34361AEB6 /* ApiReviewModels.swift in Sources */,
|
||||||
279A489F01434E0523EC1BAA /* ApiService.swift in Sources */,
|
279A489F01434E0523EC1BAA /* ApiService.swift in Sources */,
|
||||||
|
EC9F35551075A78EF7869784 /* AppBackButtonIcon.swift in Sources */,
|
||||||
B239BDCEB9F8934F1C71258C /* AppCache.swift in Sources */,
|
B239BDCEB9F8934F1C71258C /* AppCache.swift in Sources */,
|
||||||
9EDDCECCAEEB8FA4909DA9D4 /* AppCoordinator.swift in Sources */,
|
9EDDCECCAEEB8FA4909DA9D4 /* AppCoordinator.swift in Sources */,
|
||||||
9F09502CF9331F0C94BFA5F0 /* AppState.swift in Sources */,
|
9F09502CF9331F0C94BFA5F0 /* AppState.swift in Sources */,
|
||||||
@@ -782,7 +781,6 @@
|
|||||||
3689239282AADF06783CBBEA /* AuthFormatters.swift in Sources */,
|
3689239282AADF06783CBBEA /* AuthFormatters.swift in Sources */,
|
||||||
CCE23FD7706B34BDE544E05A /* Buttons.swift in Sources */,
|
CCE23FD7706B34BDE544E05A /* Buttons.swift in Sources */,
|
||||||
CEA08090E08B5E39FD0DD5D6 /* CachedRemoteImage.swift in Sources */,
|
CEA08090E08B5E39FD0DD5D6 /* CachedRemoteImage.swift in Sources */,
|
||||||
38452FD60CBDE248531DA484 /* AppBackButtonIcon.swift in Sources */,
|
|
||||||
DE499D6150C15EB046AF7963 /* CartView.swift in Sources */,
|
DE499D6150C15EB046AF7963 /* CartView.swift in Sources */,
|
||||||
70EA850C067AB6C6B87539E2 /* CheckoutTypes.swift in Sources */,
|
70EA850C067AB6C6B87539E2 /* CheckoutTypes.swift in Sources */,
|
||||||
41BE548D929D3814A736FA12 /* CheckoutView+Logic.swift in Sources */,
|
41BE548D929D3814A736FA12 /* CheckoutView+Logic.swift in Sources */,
|
||||||
@@ -872,6 +870,7 @@
|
|||||||
63AB40542AABCC3CB2390B87 /* HomeViewFilteringTests.swift in Sources */,
|
63AB40542AABCC3CB2390B87 /* HomeViewFilteringTests.swift in Sources */,
|
||||||
22E3BF78B8C2B22D14EABE8B /* ImageSourceResolverTests.swift in Sources */,
|
22E3BF78B8C2B22D14EABE8B /* ImageSourceResolverTests.swift in Sources */,
|
||||||
2FCB3403A764AD74AC3BD47C /* LegalDocumentTests.swift in Sources */,
|
2FCB3403A764AD74AC3BD47C /* LegalDocumentTests.swift in Sources */,
|
||||||
|
901A6A5A00C18FC59F764B85 /* PublicStoreDistanceTests.swift in Sources */,
|
||||||
F760557D906B860D0EA277DE /* SessionStateStoreTests.swift in Sources */,
|
F760557D906B860D0EA277DE /* SessionStateStoreTests.swift in Sources */,
|
||||||
B24B898508C8A8EF4191EC89 /* SmokeTests.swift in Sources */,
|
B24B898508C8A8EF4191EC89 /* SmokeTests.swift in Sources */,
|
||||||
7CC171B83BC4CDEC38B25F8C /* SnackbarCenterTests.swift in Sources */,
|
7CC171B83BC4CDEC38B25F8C /* SnackbarCenterTests.swift in Sources */,
|
||||||
@@ -968,6 +967,11 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Distribution";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -975,6 +979,7 @@
|
|||||||
"@loader_path/Frameworks",
|
"@loader_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.PediFoodsTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.PediFoodsTests;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_VERSION = 6;
|
SWIFT_VERSION = 6;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
@@ -990,54 +995,10 @@
|
|||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = PediFoods/PediFoods.entitlements;
|
CODE_SIGN_ENTITLEMENTS = PediFoods/PediFoods.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Distribution";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 2026.0.25.0.0.1;
|
||||||
DEVELOPMENT_TEAM = K4E5BZMM4V;
|
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
|
|
||||||
ENABLE_PREVIEWS = YES;
|
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
|
||||||
INFOPLIST_FILE = PediFoods/Info.plist;
|
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Pedi Foods";
|
|
||||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
|
||||||
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "PediFoods usa sua localização para mostrar lojas perto de você";
|
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = NO;
|
|
||||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
|
||||||
INFOPLIST_KEY_UIStatusBarStyle = UIStatusBarStyleDefault;
|
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
);
|
|
||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
|
||||||
MARKETING_VERSION = 0.0.1;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.app;
|
|
||||||
PRODUCT_NAME = PediFoods;
|
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "com.br.pedifoods.app AppStore";
|
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "PediFoods Dist XC Prov Prof";
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
|
||||||
SUPPORTS_MACCATALYST = NO;
|
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
|
||||||
SWIFT_VERSION = 6;
|
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
4424276379B7A6A98892CFBC /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
APP_ATTEST_ENVIRONMENT = development;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
|
||||||
CODE_SIGN_ENTITLEMENTS = PediFoods/PediFoods.entitlements;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
|
||||||
CODE_SIGN_STYLE = Manual;
|
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -1061,7 +1022,52 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.app;
|
||||||
PRODUCT_NAME = PediFoods;
|
PRODUCT_NAME = PediFoods;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "PediFoods Dev Prov Prof";
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LC Prov PediFoods Dist Profile";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
|
SUPPORTS_MACCATALYST = NO;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_VERSION = 6;
|
||||||
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
4424276379B7A6A98892CFBC /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
APP_ATTEST_ENVIRONMENT = development;
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = PediFoods/PediFoods.entitlements;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
CURRENT_PROJECT_VERSION = 2026.0.25.0.0.1;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
|
||||||
|
ENABLE_PREVIEWS = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = PediFoods/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "Pedi Foods";
|
||||||
|
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||||
|
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "PediFoods usa sua localização para mostrar lojas perto de você";
|
||||||
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
|
INFOPLIST_KEY_UILaunchScreen_Generation = NO;
|
||||||
|
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||||
|
INFOPLIST_KEY_UIStatusBarStyle = UIStatusBarStyleDefault;
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 0.0.1;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.app;
|
||||||
|
PRODUCT_NAME = PediFoods;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LC Prov PediFoods Dev Profile";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = NO;
|
||||||
@@ -1075,6 +1081,12 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
|
||||||
|
"DEVELOPMENT_TEAM[sdk=macosx*]" = K4E5BZMM4V;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1082,6 +1094,7 @@
|
|||||||
"@loader_path/Frameworks",
|
"@loader_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.PediFoodsTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.PediFoodsTests;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_VERSION = 6;
|
SWIFT_VERSION = 6;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
@@ -1093,9 +1106,11 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_ENABLE_OBJC_WEAK = NO;
|
CLANG_ENABLE_OBJC_WEAK = NO;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = K4E5BZMM4V;
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
|
||||||
INFOPLIST_FILE = NotificationServiceExtension/Info.plist;
|
INFOPLIST_FILE = NotificationServiceExtension/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1105,6 +1120,8 @@
|
|||||||
MARKETING_VERSION = 0.0.1;
|
MARKETING_VERSION = 0.0.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.app.NotificationService;
|
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.app.NotificationService;
|
||||||
PRODUCT_NAME = NotificationService;
|
PRODUCT_NAME = NotificationService;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LC Prov PediFoods Dev Push Profile";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_VERSION = 6;
|
SWIFT_VERSION = 6;
|
||||||
@@ -1116,6 +1133,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
DEVELOPMENT_TEAM = K4E5BZMM4V;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1190,6 +1208,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
DEVELOPMENT_TEAM = K4E5BZMM4V;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1208,9 +1227,12 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_ENABLE_OBJC_WEAK = NO;
|
CLANG_ENABLE_OBJC_WEAK = NO;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_TEAM = K4E5BZMM4V;
|
DEVELOPMENT_TEAM = "";
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
|
||||||
INFOPLIST_FILE = NotificationServiceExtension/Info.plist;
|
INFOPLIST_FILE = NotificationServiceExtension/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1220,6 +1242,8 @@
|
|||||||
MARKETING_VERSION = 0.0.1;
|
MARKETING_VERSION = 0.0.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.app.NotificationService;
|
PRODUCT_BUNDLE_IDENTIFIER = com.br.pedifoods.app.NotificationService;
|
||||||
PRODUCT_NAME = NotificationService;
|
PRODUCT_NAME = NotificationService;
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "LC Prov PediFoods Dist Push Profile";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_VERSION = 6;
|
SWIFT_VERSION = 6;
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ struct FeaturedStoreCard: View {
|
|||||||
Text("(\(store.reviews))")
|
Text("(\(store.reviews))")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(AppColors.textMuted)
|
.foregroundStyle(AppColors.textMuted)
|
||||||
|
// Empty distance means "unavailable" - drop the separator
|
||||||
|
// with it, otherwise the row ends in a dangling "·".
|
||||||
|
// See docs/plans/public-store-distance-consumer.md.
|
||||||
|
if store.distance.isEmpty == false {
|
||||||
Text("·")
|
Text("·")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(AppColors.textMuted)
|
.foregroundStyle(AppColors.textMuted)
|
||||||
@@ -60,6 +64,7 @@ struct FeaturedStoreCard: View {
|
|||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(AppColors.textMuted)
|
.foregroundStyle(AppColors.textMuted)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Text(store.statusLabel?.isEmpty == false ? (store.statusLabel ?? "Fechado") : "Fechado")
|
Text(store.statusLabel?.isEmpty == false ? (store.statusLabel ?? "Fechado") : "Fechado")
|
||||||
.font(AppTypography.heading3)
|
.font(AppTypography.heading3)
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ struct ContentView: View {
|
|||||||
@State var hasPerformedInitialLaunchBootstrap = false
|
@State var hasPerformedInitialLaunchBootstrap = false
|
||||||
@State var showLaunchSplash = true
|
@State var showLaunchSplash = true
|
||||||
@State var shouldPulseLaunchSplash = true
|
@State var shouldPulseLaunchSplash = true
|
||||||
@State var shouldPrepareAuthEntryAnimation = DefaultTokenStore().jwt == nil
|
|
||||||
@State var authEntryAnimationToken = 0
|
|
||||||
@State private var sessionExpiredObserver: NSObjectProtocol?
|
@State private var sessionExpiredObserver: NSObjectProtocol?
|
||||||
@State var cartResetObserver: Any?
|
@State var cartResetObserver: Any?
|
||||||
@State var appResumeObserver: Any?
|
@State var appResumeObserver: Any?
|
||||||
@@ -32,15 +30,15 @@ struct ContentView: View {
|
|||||||
root: $root,
|
root: $root,
|
||||||
selectedTab: $selectedTab,
|
selectedTab: $selectedTab,
|
||||||
tokenStore: tokenStore,
|
tokenStore: tokenStore,
|
||||||
appState: $appState,
|
appState: $appState
|
||||||
shouldPrepareLoginEntry: shouldPrepareAuthEntryAnimation,
|
|
||||||
authEntryAnimationToken: authEntryAnimationToken
|
|
||||||
)
|
)
|
||||||
|
.transition(.move(edge: .trailing))
|
||||||
case .main:
|
case .main:
|
||||||
if isBootstrappingSession {
|
if isBootstrappingSession {
|
||||||
sessionBootstrapLoadingView
|
sessionBootstrapLoadingView
|
||||||
} else {
|
} else {
|
||||||
MainTabView(selectedTab: $selectedTab, tokenStore: tokenStore, appState: $appState, enterAuth: enterAuthFlow)
|
MainTabView(selectedTab: $selectedTab, tokenStore: tokenStore, appState: $appState, enterAuth: enterAuthFlow)
|
||||||
|
.transition(.move(edge: .leading))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,15 +134,11 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if root == .auth {
|
if root == .auth {
|
||||||
shouldPrepareAuthEntryAnimation = true
|
|
||||||
shouldPulseLaunchSplash = false
|
shouldPulseLaunchSplash = false
|
||||||
try? await Task.sleep(nanoseconds: 180_000_000)
|
try? await Task.sleep(nanoseconds: 180_000_000)
|
||||||
withAnimation(.easeInOut(duration: 0.34)) {
|
withAnimation(.easeInOut(duration: 0.34)) {
|
||||||
showLaunchSplash = false
|
showLaunchSplash = false
|
||||||
}
|
}
|
||||||
try? await Task.sleep(nanoseconds: 360_000_000)
|
|
||||||
authEntryAnimationToken += 1
|
|
||||||
scheduleDisableAuthEntryPreparation()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,17 +404,15 @@ struct ContentView: View {
|
|||||||
enterAuthFlow()
|
enterAuthFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The only correct way to transition `root` to `.auth`: pairs the
|
/// The single funnel for entering the auth flow. `LoginView` is a
|
||||||
/// switch with the token bump `LoginView` needs to run its entry
|
/// static screen with its own `LCENavigationView` back button (sets
|
||||||
/// reveal animation. A bare `root = .auth` leaves the login screen's
|
/// `root = .main`), so no animation priming is needed here - see
|
||||||
/// hero/text/button stuck hidden - see
|
/// decisions/2026-08-27-payment-auth-lockout-clean-intro-screen.md.
|
||||||
/// decisions/2026-08-06-login-entry-animation-bug.md.
|
|
||||||
@MainActor
|
@MainActor
|
||||||
private func enterAuthFlow() {
|
private func enterAuthFlow() {
|
||||||
shouldPrepareAuthEntryAnimation = true
|
withAnimation(.easeInOut(duration: 0.3)) {
|
||||||
root = .auth
|
root = .auth
|
||||||
authEntryAnimationToken += 1
|
}
|
||||||
scheduleDisableAuthEntryPreparation()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
@@ -463,13 +455,6 @@ struct ContentView: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func scheduleDisableAuthEntryPreparation() {
|
|
||||||
Task { @MainActor in
|
|
||||||
try? await Task.sleep(nanoseconds: 900_000_000)
|
|
||||||
shouldPrepareAuthEntryAnimation = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func hasConfiguredAddress() -> Bool {
|
private func hasConfiguredAddress() -> Bool {
|
||||||
if appState.address.selectedId != nil {
|
if appState.address.selectedId != nil {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -88,6 +88,9 @@
|
|||||||
},
|
},
|
||||||
"Abrir Ajustes" : {
|
"Abrir Ajustes" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Acesse sua conta" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Acompanhamento em tempo real" : {
|
"Acompanhamento em tempo real" : {
|
||||||
|
|
||||||
@@ -346,10 +349,6 @@
|
|||||||
"comment" : "A prompt asking users to share their opinion about the delivery.",
|
"comment" : "A prompt asking users to share their opinion about the delivery.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
},
|
},
|
||||||
"Criar conta" : {
|
|
||||||
"comment" : "A link that navigates to the registration screen.",
|
|
||||||
"isCommentAutoGenerated" : true
|
|
||||||
},
|
|
||||||
"Crie sua conta" : {
|
"Crie sua conta" : {
|
||||||
"comment" : "A link that directs users to create an account.",
|
"comment" : "A link that directs users to create an account.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
@@ -748,9 +747,6 @@
|
|||||||
"Não recebeu o código?" : {
|
"Não recebeu o código?" : {
|
||||||
"comment" : "A question displayed below the button to re-send the OTP.",
|
"comment" : "A question displayed below the button to re-send the OTP.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
},
|
|
||||||
"Não tem conta ainda?" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Nenhum cartão cadastrado" : {
|
"Nenhum cartão cadastrado" : {
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ struct PublicStoreListItem: Decodable, Sendable, Identifiable {
|
|||||||
let deliveryTime: String?
|
let deliveryTime: String?
|
||||||
let deliveryFee: Double?
|
let deliveryFee: Double?
|
||||||
let minOrder: Double?
|
let minOrder: Double?
|
||||||
|
/// Kilometres from the picked city's centroid to the store - always
|
||||||
|
/// approximate, since the origin is the city rather than the visitor.
|
||||||
|
/// The server sends `0` for "unavailable" and never null; optional here
|
||||||
|
/// only so the app keeps decoding responses from before the field
|
||||||
|
/// shipped. See docs/plans/public-store-distance-consumer.md.
|
||||||
|
let distance: Double?
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PublicStoreDetail: Decodable, Sendable {
|
struct PublicStoreDetail: Decodable, Sendable {
|
||||||
@@ -56,6 +62,9 @@ struct PublicStoreDetail: Decodable, Sendable {
|
|||||||
let deliveryPrice: Double?
|
let deliveryPrice: Double?
|
||||||
let minOrder: Double?
|
let minOrder: Double?
|
||||||
let acceptPix: Bool?
|
let acceptPix: Bool?
|
||||||
|
/// Same contract as `PublicStoreListItem.distance`, but only populated
|
||||||
|
/// when the detail request carries `state`/`city`.
|
||||||
|
let distance: Double?
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maps the public (anonymous) store-detail projection onto the same models
|
// Maps the public (anonymous) store-detail projection onto the same models
|
||||||
|
|||||||
@@ -34,13 +34,31 @@ final class PublicLocationService: @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// No guest token — this route is fully public/unauthenticated per the doc.
|
/// No guest token — this route is fully public/unauthenticated per the doc.
|
||||||
func fetchStoreDetail(identifier: String) async throws -> PublicStoreDetail {
|
///
|
||||||
|
/// `state`/`city` are optional on the server and are what let it resolve
|
||||||
|
/// the city centroid the store `distance` is measured from; without them
|
||||||
|
/// the response carries `distance: 0` (see
|
||||||
|
/// docs/plans/public-store-distance-consumer.md). Defaults to whatever the
|
||||||
|
/// visitor picked in "ENTREGAR EM:".
|
||||||
|
func fetchStoreDetail(
|
||||||
|
identifier: String,
|
||||||
|
state: String? = GuestLocationStore.shared.selectedState,
|
||||||
|
city: String? = GuestLocationStore.shared.selectedCity
|
||||||
|
) async throws -> PublicStoreDetail {
|
||||||
let encodedIdentifier = identifier.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? identifier
|
let encodedIdentifier = identifier.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? identifier
|
||||||
|
var query: [URLQueryItem] = []
|
||||||
|
if let state, state.isEmpty == false {
|
||||||
|
query.append(URLQueryItem(name: "state", value: state))
|
||||||
|
}
|
||||||
|
if let city, city.isEmpty == false {
|
||||||
|
query.append(URLQueryItem(name: "city", value: city))
|
||||||
|
}
|
||||||
let req = ApiRequest(
|
let req = ApiRequest(
|
||||||
path: "/api/public/store/\(encodedIdentifier)",
|
path: "/api/public/store/\(encodedIdentifier)",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
module: .none,
|
module: .none,
|
||||||
requiresAuth: false,
|
requiresAuth: false,
|
||||||
|
queryItems: query,
|
||||||
baseURLOverride: ApiConfig.pediFoodsBFFURL
|
baseURLOverride: ApiConfig.pediFoodsBFFURL
|
||||||
)
|
)
|
||||||
let envelope: ApiEnvelope<PublicStoreDetail> = try await client.send(req)
|
let envelope: ApiEnvelope<PublicStoreDetail> = try await client.send(req)
|
||||||
|
|||||||
@@ -11,21 +11,12 @@ struct AuthFlowView: View {
|
|||||||
@Binding var selectedTab: MainTab
|
@Binding var selectedTab: MainTab
|
||||||
let tokenStore: TokenStore
|
let tokenStore: TokenStore
|
||||||
@Binding var appState: AppState
|
@Binding var appState: AppState
|
||||||
var shouldPrepareLoginEntry: Bool = false
|
|
||||||
var authEntryAnimationToken: Int = 0
|
|
||||||
|
|
||||||
@State var path: [Route] = []
|
@State var path: [Route] = []
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack(path: $path) {
|
NavigationStack(path: $path) {
|
||||||
LoginView(
|
LoginView(root: $root) { route in
|
||||||
root: $root,
|
|
||||||
selectedTab: $selectedTab,
|
|
||||||
tokenStore: tokenStore,
|
|
||||||
appState: $appState,
|
|
||||||
shouldPrepareEntryAnimation: shouldPrepareLoginEntry,
|
|
||||||
authEntryAnimationToken: authEntryAnimationToken
|
|
||||||
) { route in
|
|
||||||
path.append(route)
|
path.append(route)
|
||||||
}
|
}
|
||||||
.navigationDestination(for: Route.self) { route in
|
.navigationDestination(for: Route.self) { route in
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
#if canImport(LCEssentials)
|
||||||
|
import LCEssentials
|
||||||
|
#endif
|
||||||
|
|
||||||
struct LoginEmailView: View {
|
struct LoginEmailView: View {
|
||||||
@Binding var root: RootFlow
|
@Binding var root: RootFlow
|
||||||
@@ -11,7 +14,6 @@ struct LoginEmailView: View {
|
|||||||
@State var isLoading = false
|
@State var isLoading = false
|
||||||
@State var errorMessage: String?
|
@State var errorMessage: String?
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
@Environment(\.colorScheme) var colorScheme
|
|
||||||
|
|
||||||
@ViewBuilder private var logoImage: some View {
|
@ViewBuilder private var logoImage: some View {
|
||||||
SwiftUI.Image("pedifoods")
|
SwiftUI.Image("pedifoods")
|
||||||
@@ -19,8 +21,18 @@ struct LoginEmailView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
LCENavigationView {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
.setLeftButton(image: AnyView(AppBackButtonIcon())) { dismiss() }
|
||||||
|
.setNavigationBarBackgroundColor(AppColors.backgroundLight)
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.preferredColorScheme(.light)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var content: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
(colorScheme == .dark ? Color.black : AppColors.backgroundLight).ignoresSafeArea()
|
AppColors.backgroundLight.ignoresSafeArea()
|
||||||
|
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
logoImage
|
logoImage
|
||||||
@@ -29,7 +41,7 @@ struct LoginEmailView: View {
|
|||||||
|
|
||||||
Text("Boas-vindas!")
|
Text("Boas-vindas!")
|
||||||
.font(AppTypography.heading1)
|
.font(AppTypography.heading1)
|
||||||
.foregroundStyle(colorScheme == .dark ? Color.white : AppColors.textPrimary)
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
.padding(Edge.Set.top, 8)
|
.padding(Edge.Set.top, 8)
|
||||||
.padding(.bottom, 16)
|
.padding(.bottom, 16)
|
||||||
|
|
||||||
@@ -66,7 +78,7 @@ struct LoginEmailView: View {
|
|||||||
|
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
Text("Novo por aqui?")
|
Text("Novo por aqui?")
|
||||||
.foregroundStyle(colorScheme == .dark ? Color.white.opacity(0.8) : Color.gray)
|
.foregroundStyle(Color.gray)
|
||||||
Text("Crie sua conta")
|
Text("Crie sua conta")
|
||||||
.foregroundStyle(AppColors.primary)
|
.foregroundStyle(AppColors.primary)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
|
|||||||
@@ -1,142 +1,81 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
#if canImport(LCEssentials)
|
||||||
|
import LCEssentials
|
||||||
|
#endif
|
||||||
|
|
||||||
struct LoginView: View {
|
struct LoginView: View {
|
||||||
@Binding var root: RootFlow
|
@Binding var root: RootFlow
|
||||||
@Binding var selectedTab: MainTab
|
|
||||||
let tokenStore: TokenStore
|
|
||||||
@Binding var appState: AppState
|
|
||||||
@Environment(\.colorScheme) var colorScheme
|
|
||||||
var shouldPrepareEntryAnimation: Bool = false
|
|
||||||
var authEntryAnimationToken: Int = 0
|
|
||||||
let navigate: (Route) -> Void
|
let navigate: (Route) -> Void
|
||||||
@State var heroVisible = true
|
|
||||||
@State var textVisible = true
|
|
||||||
@State var buttonVisible = true
|
|
||||||
@State var lastAnimatedToken = 0
|
|
||||||
|
|
||||||
@ViewBuilder private var logoImage: some View {
|
@ViewBuilder private var logoImage: some View {
|
||||||
SwiftUI.Image("pedifoods")
|
SwiftUI.Image("pedifoods")
|
||||||
.resizable()
|
.resizable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder private var pinHeroImage: some View {
|
var body: some View {
|
||||||
SwiftUI.Image("pin_image_app")
|
LCENavigationView {
|
||||||
.resizable()
|
content
|
||||||
|
}
|
||||||
|
.setLeftButton(image: AnyView(AppBackButtonIcon())) {
|
||||||
|
withAnimation(.easeInOut(duration: 0.3)) { root = .main }
|
||||||
|
}
|
||||||
|
.setTitle(text: Text("Acesse sua conta").font(AppTypography.heading2).foregroundStyle(AppColors.textPrimary))
|
||||||
|
.setNavigationBarBackgroundColor(AppColors.backgroundLight)
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
// The app ships no dark theme; force light so system dark mode
|
||||||
|
// can't invert the nav bar / title against the fixed DS colors.
|
||||||
|
.preferredColorScheme(.light)
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
private var content: some View {
|
||||||
GeometryReader { geo in
|
VStack(spacing: 20) {
|
||||||
let heroHeight = max(360, geo.size.height * 0.44)
|
Spacer()
|
||||||
let logoTopInset = max(0, (geo.size.height - 180) / 2)
|
|
||||||
|
|
||||||
ZStack(alignment: .top) {
|
|
||||||
(colorScheme == .dark ? Color.black : AppColors.backgroundLight)
|
|
||||||
.ignoresSafeArea()
|
|
||||||
|
|
||||||
pinHeroImage
|
|
||||||
.scaledToFill()
|
|
||||||
.frame(height: heroHeight + 80)
|
|
||||||
.offset(y: heroVisible ? -60 : -(heroHeight + 220))
|
|
||||||
.mask(
|
|
||||||
LinearGradient(
|
|
||||||
colors: [.black, .black, .black.opacity(0.0)],
|
|
||||||
startPoint: .top,
|
|
||||||
endPoint: .bottom
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
VStack(spacing: 18) {
|
|
||||||
Spacer().frame(height: logoTopInset)
|
|
||||||
|
|
||||||
logoImage
|
logoImage
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(height: 180)
|
.frame(height: 160)
|
||||||
|
|
||||||
Text("Sua vontade, no seu tempo.\nTudo o que você precisa, em um toque.")
|
Text("Sua vontade, no seu tempo.\nTudo o que você precisa, em um toque.")
|
||||||
.font(AppTypography.heading25)
|
.font(AppTypography.heading25)
|
||||||
.foregroundStyle(colorScheme == .dark ? AppColors.textInverse : AppColors.textPrimary)
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
.multilineTextAlignment(.leading)
|
.multilineTextAlignment(.center)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
|
||||||
.padding(.horizontal, 28)
|
.padding(.horizontal, 28)
|
||||||
.opacity(textVisible ? 1.0 : 0.0)
|
|
||||||
.offset(y: textVisible ? 0 : 24)
|
|
||||||
|
|
||||||
Spacer().frame(height: 40)
|
Spacer()
|
||||||
|
|
||||||
Button {
|
VStack(spacing: 12) {
|
||||||
navigate(.loginEmail)
|
PrimaryButton(title: "Criar conta", image: Image(systemName: "arrow.right")) {
|
||||||
} label: {
|
|
||||||
PrimaryButtonLabel(title: "ENTRAR")
|
|
||||||
}
|
|
||||||
.padding(.horizontal, 28)
|
|
||||||
.tint(AppColors.tertiary)
|
|
||||||
.offset(y: buttonVisible ? 0 : 140)
|
|
||||||
.opacity(buttonVisible ? 1.0 : 0.0)
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
|
|
||||||
HStack(spacing: 6) {
|
|
||||||
Text("Não tem conta ainda?")
|
|
||||||
.foregroundStyle(colorScheme == .dark ? AppColors.textInverse.opacity(0.9) : AppColors.textPrimary)
|
|
||||||
Button("Criar conta") {
|
|
||||||
navigate(.registration)
|
navigate(.registration)
|
||||||
}
|
}
|
||||||
|
.tint(AppColors.tertiary)
|
||||||
|
|
||||||
|
SecondaryButton(title: "Entrar") {
|
||||||
|
navigate(.loginEmail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 28)
|
||||||
|
|
||||||
|
legalLinks
|
||||||
|
.padding(.top, 4)
|
||||||
|
.padding(.bottom, 24)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
|
.background(AppColors.backgroundLight.ignoresSafeArea())
|
||||||
|
}
|
||||||
|
|
||||||
|
private var legalLinks: some View {
|
||||||
|
HStack(spacing: 6) {
|
||||||
|
Button("Termos de Uso") { navigate(.terms) }
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
Text("·")
|
||||||
|
Button("Política de Privacidade") { navigate(.policy) }
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.foregroundStyle(AppColors.primary)
|
|
||||||
}
|
|
||||||
.font(AppTypography.body)
|
|
||||||
.opacity(textVisible ? 1.0 : 0.0)
|
|
||||||
.offset(y: textVisible ? 0 : 24)
|
|
||||||
|
|
||||||
Spacer().frame(height: 12)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ignoresSafeArea()
|
|
||||||
.onAppear {
|
|
||||||
if shouldPrepareEntryAnimation {
|
|
||||||
applyHiddenStateWithoutAnimation()
|
|
||||||
} else {
|
|
||||||
showFinalStateWithoutAnimation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.task(id: authEntryAnimationToken) {
|
|
||||||
await runEntryAnimationIfNeeded(for: authEntryAnimationToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainActor
|
|
||||||
private func applyHiddenStateWithoutAnimation() {
|
|
||||||
heroVisible = false
|
|
||||||
textVisible = false
|
|
||||||
buttonVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainActor
|
|
||||||
private func showFinalStateWithoutAnimation() {
|
|
||||||
heroVisible = true
|
|
||||||
textVisible = true
|
|
||||||
buttonVisible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainActor
|
|
||||||
private func runEntryAnimationIfNeeded(for token: Int) async {
|
|
||||||
guard token > 0 else { return }
|
|
||||||
guard token != lastAnimatedToken else { return }
|
|
||||||
lastAnimatedToken = token
|
|
||||||
|
|
||||||
applyHiddenStateWithoutAnimation()
|
|
||||||
try? await Task.sleep(nanoseconds: 40_000_000)
|
|
||||||
|
|
||||||
withAnimation(.spring(response: 0.64, dampingFraction: 0.9)) {
|
|
||||||
heroVisible = true
|
|
||||||
}
|
|
||||||
try? await Task.sleep(nanoseconds: 160_000_000)
|
|
||||||
withAnimation(.easeOut(duration: 0.42)) {
|
|
||||||
textVisible = true
|
|
||||||
}
|
|
||||||
try? await Task.sleep(nanoseconds: 150_000_000)
|
|
||||||
withAnimation(.spring(response: 0.52, dampingFraction: 0.86)) {
|
|
||||||
buttonVisible = true
|
|
||||||
}
|
}
|
||||||
|
.font(.system(size: 14, weight: .medium))
|
||||||
|
.foregroundStyle(AppColors.textMuted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
LoginView(root: .constant(.auth), navigate: { _ in })
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UIKit
|
import UIKit
|
||||||
|
#if canImport(LCEssentials)
|
||||||
|
import LCEssentials
|
||||||
|
#endif
|
||||||
|
|
||||||
struct OtpView: View {
|
struct OtpView: View {
|
||||||
private let resendDelaySeconds = 45
|
private let resendDelaySeconds = 45
|
||||||
@@ -21,13 +24,23 @@ struct OtpView: View {
|
|||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
LCENavigationView {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
.setLeftButton(image: AnyView(AppBackButtonIcon())) { dismiss() }
|
||||||
|
.setNavigationBarBackgroundColor(AppColors.backgroundLight)
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.preferredColorScheme(.light)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var content: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
SwiftUI.Image("pedifoods")
|
SwiftUI.Image("pedifoods")
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 74, height: 74)
|
.frame(width: 74, height: 74)
|
||||||
.padding(.top, 140)
|
.padding(.top, 48)
|
||||||
|
|
||||||
Text("Verificação")
|
Text("Verificação")
|
||||||
.font(AppTypography.heading1)
|
.font(AppTypography.heading1)
|
||||||
@@ -122,7 +135,6 @@ struct OtpView: View {
|
|||||||
}
|
}
|
||||||
.scrollDismissesKeyboard(.interactively)
|
.scrollDismissesKeyboard(.interactively)
|
||||||
.background(AppColors.backgroundLight)
|
.background(AppColors.backgroundLight)
|
||||||
.ignoresSafeArea()
|
|
||||||
.onAppear {
|
.onAppear {
|
||||||
isOtpFocused = true
|
isOtpFocused = true
|
||||||
startResendCooldown()
|
startResendCooldown()
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
#if canImport(LCEssentials)
|
||||||
|
import LCEssentials
|
||||||
|
#endif
|
||||||
|
|
||||||
struct RegistrationView: View {
|
struct RegistrationView: View {
|
||||||
@Binding var root: RootFlow
|
@Binding var root: RootFlow
|
||||||
@@ -12,7 +15,6 @@ struct RegistrationView: View {
|
|||||||
@State var isLoading = false
|
@State var isLoading = false
|
||||||
@State var errorMessage: String?
|
@State var errorMessage: String?
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
@Environment(\.colorScheme) var colorScheme
|
|
||||||
let navigate: (Route) -> Void
|
let navigate: (Route) -> Void
|
||||||
|
|
||||||
private var isFormValid: Bool { !name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !email.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !phone.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && acceptedTerms }
|
private var isFormValid: Bool { !name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !email.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !phone.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && acceptedTerms }
|
||||||
@@ -23,8 +25,18 @@ struct RegistrationView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
LCENavigationView {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
.setLeftButton(image: AnyView(AppBackButtonIcon())) { dismiss() }
|
||||||
|
.setNavigationBarBackgroundColor(AppColors.backgroundLight)
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.preferredColorScheme(.light)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var content: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
(colorScheme == .dark ? Color.black : AppColors.backgroundLight).ignoresSafeArea()
|
AppColors.backgroundLight.ignoresSafeArea()
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
@@ -34,11 +46,11 @@ struct RegistrationView: View {
|
|||||||
|
|
||||||
Text("Crie sua conta")
|
Text("Crie sua conta")
|
||||||
.font(AppTypography.heading1)
|
.font(AppTypography.heading1)
|
||||||
.foregroundStyle(colorScheme == .dark ? Color.white : AppColors.textPrimary)
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
|
|
||||||
Text("Preencha os dados abaixo para começar.")
|
Text("Preencha os dados abaixo para começar.")
|
||||||
.font(AppTypography.body)
|
.font(AppTypography.body)
|
||||||
.foregroundStyle(colorScheme == .dark ? Color.white : AppColors.textPrimary)
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
.padding(.bottom, 20)
|
.padding(.bottom, 20)
|
||||||
|
|
||||||
@@ -64,7 +76,7 @@ struct RegistrationView: View {
|
|||||||
|
|
||||||
Group {
|
Group {
|
||||||
Text("Ao se cadastrar, você concorda com nossos [Termos de Uso](app://terms) e [Política de Privacidade](app://policy)")
|
Text("Ao se cadastrar, você concorda com nossos [Termos de Uso](app://terms) e [Política de Privacidade](app://policy)")
|
||||||
.foregroundStyle(colorScheme == .dark ? Color.white : AppColors.textPrimary)
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
.tint(AppColors.primary)
|
.tint(AppColors.primary)
|
||||||
.environment(\.openURL, OpenURLAction { url in
|
.environment(\.openURL, OpenURLAction { url in
|
||||||
guard url.scheme == "app" else { return .handled }
|
guard url.scheme == "app" else { return .handled }
|
||||||
@@ -98,7 +110,7 @@ struct RegistrationView: View {
|
|||||||
|
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
Text("Já tem uma conta?")
|
Text("Já tem uma conta?")
|
||||||
.foregroundStyle(colorScheme == .dark ? Color.white.opacity(0.8) : AppColors.textPrimary)
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
NavigationLink("Entrar") {
|
NavigationLink("Entrar") {
|
||||||
LoginEmailView(root: $root, selectedTab: $selectedTab, tokenStore: tokenStore, appState: $appState, navigate: navigate)
|
LoginEmailView(root: $root, selectedTab: $selectedTab, tokenStore: tokenStore, appState: $appState, navigate: navigate)
|
||||||
}
|
}
|
||||||
@@ -110,7 +122,6 @@ struct RegistrationView: View {
|
|||||||
Spacer().frame(height: 12)
|
Spacer().frame(height: 12)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, -40)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ extension HomeView {
|
|||||||
|
|
||||||
extension StoreSummary {
|
extension StoreSummary {
|
||||||
/// Maps the public-locator DTO onto the same model HomeView already
|
/// Maps the public-locator DTO onto the same model HomeView already
|
||||||
/// renders — distance/positiveReviews don't exist in that response.
|
/// renders — positiveReviews doesn't exist in that response.
|
||||||
init(publicItem: PublicStoreListItem) {
|
init(publicItem: PublicStoreListItem) {
|
||||||
self.id = publicItem.id
|
self.id = publicItem.id
|
||||||
self.name = publicItem.name ?? "Loja"
|
self.name = publicItem.name ?? "Loja"
|
||||||
@@ -189,7 +189,10 @@ extension StoreSummary {
|
|||||||
self.positiveReviews = nil
|
self.positiveReviews = nil
|
||||||
self.deliveryTime = publicItem.deliveryTime
|
self.deliveryTime = publicItem.deliveryTime
|
||||||
self.deliveryFee = publicItem.deliveryFee
|
self.deliveryFee = publicItem.deliveryFee
|
||||||
self.distance = nil
|
// The contract uses `0` for "no distance available"; normalize it to
|
||||||
|
// nil here so every downstream consumer (card label, max-distance
|
||||||
|
// filter) sees one representation of "unknown".
|
||||||
|
self.distance = (publicItem.distance ?? 0) > 0 ? publicItem.distance : nil
|
||||||
self.isOpen = publicItem.isOpen
|
self.isOpen = publicItem.isOpen
|
||||||
self.statusLabel = publicItem.statusLabel
|
self.statusLabel = publicItem.statusLabel
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,8 +82,13 @@ extension HomeView {
|
|||||||
resolveStoreMediaURL(appState.profile.profilePicture)
|
resolveStoreMediaURL(appState.profile.profilePicture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Empty string means "no distance to show" - the caller omits the whole
|
||||||
|
/// segment rather than labelling it. Per the API contract
|
||||||
|
/// (docs/plans/public-store-distance-consumer.md) the server never sends
|
||||||
|
/// null and uses `0` for "unavailable", so both that and a missing value
|
||||||
|
/// collapse to the same empty result.
|
||||||
func formatDistance(_ distance: Double?) -> String {
|
func formatDistance(_ distance: Double?) -> String {
|
||||||
guard let distance else { return "Distância indisponível" }
|
guard let distance, distance > 0 else { return "" }
|
||||||
if distance >= 1 {
|
if distance >= 1 {
|
||||||
return String(format: "%.1f km", distance)
|
return String(format: "%.1f km", distance)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,8 +109,13 @@ extension StoreDetailView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
|
// No distance available: drop the tile and its divider
|
||||||
|
// instead of showing a placeholder - see
|
||||||
|
// docs/plans/public-store-distance-consumer.md.
|
||||||
|
if hasStoreDistance {
|
||||||
statItem(title: "DISTÂNCIA", value: distanceValueLabel)
|
statItem(title: "DISTÂNCIA", value: distanceValueLabel)
|
||||||
Divider().frame(height: 34)
|
Divider().frame(height: 34)
|
||||||
|
}
|
||||||
if let deliveryTime = info?.deliveryTime {
|
if let deliveryTime = info?.deliveryTime {
|
||||||
statItem(title: "TEMPO MIN.", value: deliveryTime+" min.")
|
statItem(title: "TEMPO MIN.", value: deliveryTime+" min.")
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -57,12 +57,14 @@ extension StoreDetailView {
|
|||||||
return "R$ --"
|
return "R$ --"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Already formatted upstream by `HomeView.formatDistance`, which returns
|
||||||
|
/// an empty string when there's no distance to show.
|
||||||
var distanceValueLabel: String {
|
var distanceValueLabel: String {
|
||||||
let raw = (storeDistance ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
|
(storeDistance ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
if raw.isEmpty {
|
|
||||||
return "--"
|
|
||||||
}
|
}
|
||||||
return raw
|
|
||||||
|
var hasStoreDistance: Bool {
|
||||||
|
distanceValueLabel.isEmpty == false
|
||||||
}
|
}
|
||||||
|
|
||||||
var isStoreOpen: Bool {
|
var isStoreOpen: Bool {
|
||||||
|
|||||||
@@ -63,5 +63,17 @@ func formatDistanceSwitchesUnitsAtOneKm() {
|
|||||||
#expect(view.formatDistance(0.5) == "500 m")
|
#expect(view.formatDistance(0.5) == "500 m")
|
||||||
#expect(view.formatDistance(1.0) == "1.0 km")
|
#expect(view.formatDistance(1.0) == "1.0 km")
|
||||||
#expect(view.formatDistance(2.3) == "2.3 km")
|
#expect(view.formatDistance(2.3) == "2.3 km")
|
||||||
#expect(view.formatDistance(nil) == "Distância indisponível")
|
}
|
||||||
|
|
||||||
|
/// Contract (docs/plans/public-store-distance-consumer.md): the API never
|
||||||
|
/// sends null - `0` means "no distance available". Both that and a missing
|
||||||
|
/// value render as an empty string so the caller omits the segment
|
||||||
|
/// entirely, instead of showing "Distância indisponível" or "0 m".
|
||||||
|
@Test("formatDistance renders nothing when the distance is missing or zero")
|
||||||
|
@MainActor
|
||||||
|
func formatDistanceIsEmptyWhenUnavailable() {
|
||||||
|
let view = makeHomeView()
|
||||||
|
#expect(view.formatDistance(nil) == "")
|
||||||
|
#expect(view.formatDistance(0) == "")
|
||||||
|
#expect(view.formatDistance(-1) == "")
|
||||||
}
|
}
|
||||||
|
|||||||
49
PediFoodsTests/PublicStoreDistanceTests.swift
Normal file
49
PediFoodsTests/PublicStoreDistanceTests.swift
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import Foundation
|
||||||
|
import Testing
|
||||||
|
@testable import PediFoods
|
||||||
|
|
||||||
|
/// Covers the public-locator distance contract documented in
|
||||||
|
/// docs/plans/public-store-distance-consumer.md: the server sends
|
||||||
|
/// `distance` as a number (never null) where `0` means "unavailable", and
|
||||||
|
/// the app collapses that to `nil` so a single representation of "unknown"
|
||||||
|
/// reaches the card label and the max-distance filter.
|
||||||
|
private func decode<T: Decodable>(_ type: T.Type, _ json: String) throws -> T {
|
||||||
|
try JSONDecoder().decode(T.self, from: Data(json.utf8))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("PublicStoreListItem decodes the distance field")
|
||||||
|
func publicStoreListItemDecodesDistance() throws {
|
||||||
|
let item = try decode(PublicStoreListItem.self, #"{"id":"1","distance":3.4}"#)
|
||||||
|
#expect(item.distance == 3.4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The field ships on the backend after the app - a response without it
|
||||||
|
/// must still decode rather than throwing.
|
||||||
|
@Test("PublicStoreListItem still decodes a response with no distance field")
|
||||||
|
func publicStoreListItemDecodesWithoutDistance() throws {
|
||||||
|
let item = try decode(PublicStoreListItem.self, #"{"id":"1"}"#)
|
||||||
|
#expect(item.distance == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("PublicStoreDetail decodes the distance field")
|
||||||
|
func publicStoreDetailDecodesDistance() throws {
|
||||||
|
let detail = try decode(PublicStoreDetail.self, #"{"id":"1","distance":1.2}"#)
|
||||||
|
#expect(detail.distance == 1.2)
|
||||||
|
let without = try decode(PublicStoreDetail.self, #"{"id":"1"}"#)
|
||||||
|
#expect(without.distance == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("StoreSummary carries a real public distance through")
|
||||||
|
func storeSummaryKeepsPublicDistance() throws {
|
||||||
|
let item = try decode(PublicStoreListItem.self, #"{"id":"1","name":"A","distance":2.5}"#)
|
||||||
|
#expect(StoreSummary(publicItem: item).distance == 2.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test("StoreSummary maps the unavailable sentinel and a missing distance to nil")
|
||||||
|
func storeSummaryNormalizesUnavailableDistance() throws {
|
||||||
|
let zero = try decode(PublicStoreListItem.self, #"{"id":"1","name":"A","distance":0}"#)
|
||||||
|
#expect(StoreSummary(publicItem: zero).distance == nil)
|
||||||
|
|
||||||
|
let absent = try decode(PublicStoreListItem.self, #"{"id":"1","name":"A"}"#)
|
||||||
|
#expect(StoreSummary(publicItem: absent).distance == nil)
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
/// Covers the Profile tab's logged-out state (`ProfileLoggedOutView`) -
|
/// Covers the Profile tab's logged-out state (`ProfileLoggedOutView`) and
|
||||||
/// confirmed reachable. Actually logging in is blocked by a separate
|
/// the auth intro screen (`LoginView`) it opens.
|
||||||
/// navigation issue in LoginView's entry-reveal animation, documented in
|
|
||||||
/// decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md - not
|
|
||||||
/// covered here.
|
|
||||||
final class ProfileLoggedOutFlowTests: XCTestCase {
|
final class ProfileLoggedOutFlowTests: XCTestCase {
|
||||||
override func setUpWithError() throws {
|
override func setUpWithError() throws {
|
||||||
continueAfterFailure = false
|
continueAfterFailure = false
|
||||||
@@ -20,18 +17,52 @@ final class ProfileLoggedOutFlowTests: XCTestCase {
|
|||||||
XCTAssertTrue(app.buttons["Entrar ou Cadastrar"].isHittable)
|
XCTAssertTrue(app.buttons["Entrar ou Cadastrar"].isHittable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTappingLoginButtonDoesNotCrash() throws {
|
/// The auth intro screen must offer both entry points plus the legal
|
||||||
|
/// links, and — the reason App Review rejected the build in 2026-08 —
|
||||||
|
/// a working way back out (its `LCENavigationView` back button, which
|
||||||
|
/// sets `root = .main`).
|
||||||
|
func testAuthIntroScreenShowsChoicesAndCanGoBack() throws {
|
||||||
let app = XCUIApplication()
|
let app = XCUIApplication()
|
||||||
app.launch()
|
app.launch()
|
||||||
XCTAssertTrue(app.reachLoggedOutProfile())
|
XCTAssertTrue(app.reachLoggedOutProfile())
|
||||||
|
|
||||||
app.buttons["Entrar ou Cadastrar"].tap()
|
app.buttons["Entrar ou Cadastrar"].tap()
|
||||||
sleep(2)
|
|
||||||
|
|
||||||
// Known limitation (see decisions doc): the login screen's entry
|
XCTAssertTrue(app.buttons["Criar conta"].waitForExistence(timeout: 5), "Auth intro missing 'Criar conta'")
|
||||||
// animation doesn't reliably reveal when navigating here from an
|
XCTAssertTrue(app.buttons["Entrar"].exists, "Auth intro missing 'Entrar'")
|
||||||
// already-running guest session, so this only asserts the app is
|
XCTAssertTrue(app.buttons["Termos de Uso"].exists, "Auth intro missing 'Termos de Uso' link")
|
||||||
// still alive and responsive, not that login itself completes.
|
XCTAssertTrue(app.buttons["Política de Privacidade"].exists, "Auth intro missing 'Política de Privacidade' link")
|
||||||
XCTAssertEqual(app.state, .runningForeground)
|
|
||||||
|
let backButton = app.buttons.matching(NSPredicate(format: "label == %@", "Back")).firstMatch
|
||||||
|
XCTAssertTrue(backButton.exists, "Auth intro has no back button — user is trapped")
|
||||||
|
backButton.tap()
|
||||||
|
|
||||||
|
// Back out of `.auth` lands on the main tab bar again.
|
||||||
|
XCTAssertTrue(app.buttons["Home"].waitForExistence(timeout: 5), "Back button did not return to the main flow")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The pushed auth screens (Registration, LoginEmail) must carry the
|
||||||
|
/// app's standard `AppBackButtonIcon` via `LCENavigationView`, not the
|
||||||
|
/// oversized iOS 26 system glass back button.
|
||||||
|
func testPushedAuthScreensUseAppBackButton() throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launch()
|
||||||
|
XCTAssertTrue(app.reachLoggedOutProfile())
|
||||||
|
app.buttons["Entrar ou Cadastrar"].tap()
|
||||||
|
|
||||||
|
XCTAssertTrue(app.buttons["Criar conta"].waitForExistence(timeout: 5))
|
||||||
|
app.buttons["Criar conta"].tap()
|
||||||
|
XCTAssertTrue(app.staticTexts["Crie sua conta"].waitForExistence(timeout: 5))
|
||||||
|
let regBack = app.buttons.matching(NSPredicate(format: "label == %@", "Back")).firstMatch
|
||||||
|
XCTAssertTrue(regBack.exists, "Registration screen has no LCENavigationView back button")
|
||||||
|
regBack.tap()
|
||||||
|
|
||||||
|
XCTAssertTrue(app.buttons["Entrar"].waitForExistence(timeout: 5))
|
||||||
|
app.buttons["Entrar"].tap()
|
||||||
|
XCTAssertTrue(app.staticTexts["Boas-vindas!"].waitForExistence(timeout: 5))
|
||||||
|
let loginBack = app.buttons.matching(NSPredicate(format: "label == %@", "Back")).firstMatch
|
||||||
|
XCTAssertTrue(loginBack.exists, "Login e-mail screen has no LCENavigationView back button")
|
||||||
|
loginBack.tap()
|
||||||
|
XCTAssertTrue(app.buttons["Criar conta"].waitForExistence(timeout: 5), "Back did not return to the auth intro")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ extension XCUIApplication {
|
|||||||
|
|
||||||
buttons["Entrar ou Cadastrar"].tap()
|
buttons["Entrar ou Cadastrar"].tap()
|
||||||
|
|
||||||
let entrarButton = buttons["ENTRAR"]
|
let entrarButton = buttons["Entrar"]
|
||||||
guard entrarButton.waitForExistence(timeout: 5) else { return false }
|
guard entrarButton.waitForExistence(timeout: 5) else { return false }
|
||||||
entrarButton.tap()
|
entrarButton.tap()
|
||||||
|
|
||||||
|
|||||||
47
project.yml
47
project.yml
@@ -52,17 +52,19 @@ targets:
|
|||||||
INFOPLIST_KEY_UIStatusBarStyle: UIStatusBarStyleDefault
|
INFOPLIST_KEY_UIStatusBarStyle: UIStatusBarStyleDefault
|
||||||
configs:
|
configs:
|
||||||
Debug:
|
Debug:
|
||||||
|
CODE_SIGN_IDENTITY: "Apple Development"
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]": "iPhone Developer"
|
||||||
DEVELOPMENT_TEAM: ""
|
DEVELOPMENT_TEAM: ""
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]": K4E5BZMM4V
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]": K4E5BZMM4V
|
||||||
PROVISIONING_PROFILE_SPECIFIER: ""
|
PROVISIONING_PROFILE_SPECIFIER: ""
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]": "PediFoods Dev Prov Prof"
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]": "LC Prov PediFoods Dev Profile"
|
||||||
Release:
|
Release:
|
||||||
DEVELOPMENT_TEAM: K4E5BZMM4V
|
CODE_SIGN_IDENTITY: "Apple Development"
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]": K4E5BZMM4V
|
|
||||||
CODE_SIGN_IDENTITY: "Apple Distribution"
|
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]": "iPhone Distribution"
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]": "iPhone Distribution"
|
||||||
PROVISIONING_PROFILE_SPECIFIER: "com.br.pedifoods.app AppStore"
|
DEVELOPMENT_TEAM: ""
|
||||||
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]": "PediFoods Dist XC Prov Prof"
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]": K4E5BZMM4V
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER: ""
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]": "LC Prov PediFoods Dist Profile"
|
||||||
attributes:
|
attributes:
|
||||||
SystemCapabilities:
|
SystemCapabilities:
|
||||||
com.apple.Push:
|
com.apple.Push:
|
||||||
@@ -80,12 +82,25 @@ targets:
|
|||||||
MARKETING_VERSION: 0.0.1
|
MARKETING_VERSION: 0.0.1
|
||||||
CURRENT_PROJECT_VERSION: 1
|
CURRENT_PROJECT_VERSION: 1
|
||||||
INFOPLIST_FILE: NotificationServiceExtension/Info.plist
|
INFOPLIST_FILE: NotificationServiceExtension/Info.plist
|
||||||
CODE_SIGN_STYLE: Automatic
|
CODE_SIGN_STYLE: Manual
|
||||||
DEVELOPMENT_TEAM: K4E5BZMM4V
|
|
||||||
SWIFT_VERSION: "6"
|
SWIFT_VERSION: "6"
|
||||||
TARGETED_DEVICE_FAMILY: "1"
|
TARGETED_DEVICE_FAMILY: "1"
|
||||||
SKIP_INSTALL: YES
|
SKIP_INSTALL: YES
|
||||||
CLANG_ENABLE_OBJC_WEAK: NO
|
CLANG_ENABLE_OBJC_WEAK: NO
|
||||||
|
configs:
|
||||||
|
Debug:
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]": "iPhone Developer"
|
||||||
|
DEVELOPMENT_TEAM: ""
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]": K4E5BZMM4V
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER: ""
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]": "LC Prov PediFoods Dev Push Profile"
|
||||||
|
Release:
|
||||||
|
CODE_SIGN_IDENTITY: "Apple Development"
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]": "iPhone Distribution"
|
||||||
|
DEVELOPMENT_TEAM: ""
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]": K4E5BZMM4V
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER: ""
|
||||||
|
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]": "LC Prov PediFoods Dist Push Profile"
|
||||||
|
|
||||||
PediFoodsTests:
|
PediFoodsTests:
|
||||||
type: bundle.unit-test
|
type: bundle.unit-test
|
||||||
@@ -98,6 +113,21 @@ targets:
|
|||||||
base:
|
base:
|
||||||
SWIFT_VERSION: "6"
|
SWIFT_VERSION: "6"
|
||||||
GENERATE_INFOPLIST_FILE: YES
|
GENERATE_INFOPLIST_FILE: YES
|
||||||
|
CODE_SIGN_STYLE: Manual
|
||||||
|
configs:
|
||||||
|
Debug:
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]": "iPhone Developer"
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]": "Apple Development"
|
||||||
|
DEVELOPMENT_TEAM: ""
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]": K4E5BZMM4V
|
||||||
|
"DEVELOPMENT_TEAM[sdk=macosx*]": K4E5BZMM4V
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER: ""
|
||||||
|
Release:
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]": "Apple Distribution"
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]": "-"
|
||||||
|
DEVELOPMENT_TEAM: ""
|
||||||
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]": K4E5BZMM4V
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER: ""
|
||||||
|
|
||||||
PediFoodsUITests:
|
PediFoodsUITests:
|
||||||
type: bundle.ui-testing
|
type: bundle.ui-testing
|
||||||
@@ -110,6 +140,7 @@ targets:
|
|||||||
base:
|
base:
|
||||||
SWIFT_VERSION: "6"
|
SWIFT_VERSION: "6"
|
||||||
GENERATE_INFOPLIST_FILE: YES
|
GENERATE_INFOPLIST_FILE: YES
|
||||||
|
DEVELOPMENT_TEAM: K4E5BZMM4V
|
||||||
|
|
||||||
schemes:
|
schemes:
|
||||||
PediFoods:
|
PediFoods:
|
||||||
|
|||||||
Reference in New Issue
Block a user