diff --git a/AlloVictor.xcodeproj/project.pbxproj b/AlloVictor.xcodeproj/project.pbxproj index 6758f8e..d34a208 100644 --- a/AlloVictor.xcodeproj/project.pbxproj +++ b/AlloVictor.xcodeproj/project.pbxproj @@ -8,17 +8,113 @@ /* Begin PBXBuildFile section */ 524FA6002BCACDCE00133747 /* AlloVictorApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA5FF2BCACDCE00133747 /* AlloVictorApp.swift */; }; - 524FA6022BCACDCE00133747 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6012BCACDCE00133747 /* ContentView.swift */; }; + 524FA6022BCACDCE00133747 /* OffersListScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6012BCACDCE00133747 /* OffersListScreen.swift */; }; 524FA6042BCACDCF00133747 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 524FA6032BCACDCF00133747 /* Assets.xcassets */; }; 524FA6072BCACDCF00133747 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 524FA6062BCACDCF00133747 /* Preview Assets.xcassets */; }; + 524FA60F2BCACF0500133747 /* Screen1.json in Resources */ = {isa = PBXBuildFile; fileRef = 524FA60E2BCACF0500133747 /* Screen1.json */; }; + 524FA6112BCACF3A00133747 /* Screen2.json in Resources */ = {isa = PBXBuildFile; fileRef = 524FA6102BCACF3A00133747 /* Screen2.json */; }; + 524FA61B2BCAD04B00133747 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA61A2BCAD04B00133747 /* Constants.swift */; }; + 524FA61D2BCAD0F100133747 /* OfferListResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA61C2BCAD0F100133747 /* OfferListResponseDTO.swift */; }; + 524FA61F2BCAD0FD00133747 /* OfferDetailsResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA61E2BCAD0FD00133747 /* OfferDetailsResponseDTO.swift */; }; + 524FA6212BCAD22D00133747 /* HTTPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6202BCAD22D00133747 /* HTTPClient.swift */; }; + 524FA6232BCAD29000133747 /* AlloVictorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6222BCAD29000133747 /* AlloVictorViewModel.swift */; }; + 524FA6252BCAD58400133747 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6242BCAD58400133747 /* AppState.swift */; }; + 524FA6272BCAE1C500133747 /* OfferListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6262BCAE1C500133747 /* OfferListView.swift */; }; + 524FA62A2BCAEC0B00133747 /* CachedAsyncImage in Frameworks */ = {isa = PBXBuildFile; productRef = 524FA6292BCAEC0B00133747 /* CachedAsyncImage */; }; + 524FA62C2BCAF2CF00133747 /* AlloFlashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA62B2BCAF2CF00133747 /* AlloFlashView.swift */; }; + 524FA63D2BCBF4C300133747 /* tt_chocolates_light.otf in Resources */ = {isa = PBXBuildFile; fileRef = 524FA62F2BCBF4C300133747 /* tt_chocolates_light.otf */; }; + 524FA63E2BCBF4C300133747 /* tt_chocolates_extralight.otf in Resources */ = {isa = PBXBuildFile; fileRef = 524FA6302BCBF4C300133747 /* tt_chocolates_extralight.otf */; }; + 524FA63F2BCBF4C300133747 /* tt_chocolates_regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 524FA6312BCBF4C300133747 /* tt_chocolates_regular.otf */; }; + 524FA6412BCBF4C300133747 /* tt_chocolates_demibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 524FA6332BCBF4C300133747 /* tt_chocolates_demibold.otf */; }; + 524FA6442BCBF4C300133747 /* tt_chocolates_extrabold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 524FA6362BCBF4C300133747 /* tt_chocolates_extrabold.otf */; }; + 524FA6452BCBF4C300133747 /* tt_chocolates_bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 524FA6372BCBF4C300133747 /* tt_chocolates_bold.otf */; }; + 524FA6492BCBF4C300133747 /* tt_chocolates_medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 524FA63B2BCBF4C300133747 /* tt_chocolates_medium.otf */; }; + 524FA64D2BCBFA3000133747 /* TextModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA64C2BCBFA3000133747 /* TextModifier.swift */; }; + 524FA64F2BCC0AA100133747 /* OfferDetailsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA64E2BCC0AA100133747 /* OfferDetailsScreen.swift */; }; + 524FA6512BCC115B00133747 /* OffererUserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6502BCC115B00133747 /* OffererUserView.swift */; }; + 524FA6532BCC326500133747 /* ShareView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6522BCC326500133747 /* ShareView.swift */; }; + 524FA6552BCC339A00133747 /* OfferDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6542BCC339A00133747 /* OfferDetailsView.swift */; }; + 524FA6572BCC34E900133747 /* OfferSocialView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 524FA6562BCC34E800133747 /* OfferSocialView.swift */; }; + 525ED7342BCD257C00FE6109 /* AvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525ED7332BCD257C00FE6109 /* AvatarView.swift */; }; + 52B222022BD1492600B55575 /* ShowFullPictureScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222012BD1492600B55575 /* ShowFullPictureScreen.swift */; }; + 52B222112BD1631600B55575 /* NotFoundScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222102BD1631600B55575 /* NotFoundScreen.swift */; }; + 52B222132BD16DC800B55575 /* OfferDetailsBodyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222122BD16DC800B55575 /* OfferDetailsBodyView.swift */; }; + 52B222172BD1737500B55575 /* Extension+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222162BD1737500B55575 /* Extension+View.swift */; }; + 52B222192BD173FF00B55575 /* OffererUserRatingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222182BD173FF00B55575 /* OffererUserRatingView.swift */; }; + 52B2221B2BD1749E00B55575 /* OffererUserInfos.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B2221A2BD1749E00B55575 /* OffererUserInfos.swift */; }; + 52B2221D2BD1756100B55575 /* OffererUserProStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B2221C2BD1756100B55575 /* OffererUserProStatusView.swift */; }; + 52B2221F2BD175E300B55575 /* OffererUserGallery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B2221E2BD175E300B55575 /* OffererUserGallery.swift */; }; + 52B222232BD1782700B55575 /* OfferHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222222BD1782700B55575 /* OfferHeaderView.swift */; }; + 52B222252BD178D000B55575 /* OfferBodyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222242BD178D000B55575 /* OfferBodyView.swift */; }; + 52B222292BD17A6300B55575 /* Offer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222282BD17A6300B55575 /* Offer.swift */; }; + 52B2222B2BD17A7F00B55575 /* Relationships.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B2222A2BD17A7F00B55575 /* Relationships.swift */; }; + 52B2222D2BD17A9100B55575 /* Leaseholder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B2222C2BD17A9100B55575 /* Leaseholder.swift */; }; + 52B2222F2BD17AA100B55575 /* Social.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B2222E2BD17AA100B55575 /* Social.swift */; }; + 52B222312BD17ACB00B55575 /* OfferPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222302BD17ACB00B55575 /* OfferPicture.swift */; }; + 52B222332BD17ADC00B55575 /* OfferPictureUrls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222322BD17ADC00B55575 /* OfferPictureUrls.swift */; }; + 52B222352BD17AEB00B55575 /* OfferersUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222342BD17AEB00B55575 /* OfferersUser.swift */; }; + 52B222372BD17B0100B55575 /* OfferersUserMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222362BD17B0100B55575 /* OfferersUserMeta.swift */; }; + 52B222392BD17B1200B55575 /* GalleryPicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222382BD17B1200B55575 /* GalleryPicture.swift */; }; + 52B2223B2BD17BD100B55575 /* OfferDetailsAwnserCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B2223A2BD17BD100B55575 /* OfferDetailsAwnserCountView.swift */; }; + 52B2223F2BD17D5800B55575 /* OfferDetailsGalleryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B2223E2BD17D5800B55575 /* OfferDetailsGalleryView.swift */; }; + 52B222412BD17DF100B55575 /* OfferDetailsLeaseholderInfosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222402BD17DF100B55575 /* OfferDetailsLeaseholderInfosView.swift */; }; + 52B222432BD1864100B55575 /* OfferDetailsMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B222422BD1864100B55575 /* OfferDetailsMapView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 524FA5FC2BCACDCE00133747 /* AlloVictor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AlloVictor.app; sourceTree = BUILT_PRODUCTS_DIR; }; 524FA5FF2BCACDCE00133747 /* AlloVictorApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlloVictorApp.swift; sourceTree = ""; }; - 524FA6012BCACDCE00133747 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 524FA6012BCACDCE00133747 /* OffersListScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OffersListScreen.swift; sourceTree = ""; }; 524FA6032BCACDCF00133747 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 524FA6062BCACDCF00133747 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 524FA60E2BCACF0500133747 /* Screen1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Screen1.json; sourceTree = ""; }; + 524FA6102BCACF3A00133747 /* Screen2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Screen2.json; sourceTree = ""; }; + 524FA61A2BCAD04B00133747 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; + 524FA61C2BCAD0F100133747 /* OfferListResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferListResponseDTO.swift; sourceTree = ""; }; + 524FA61E2BCAD0FD00133747 /* OfferDetailsResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferDetailsResponseDTO.swift; sourceTree = ""; }; + 524FA6202BCAD22D00133747 /* HTTPClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPClient.swift; sourceTree = ""; }; + 524FA6222BCAD29000133747 /* AlloVictorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlloVictorViewModel.swift; sourceTree = ""; }; + 524FA6242BCAD58400133747 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; + 524FA6262BCAE1C500133747 /* OfferListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferListView.swift; sourceTree = ""; }; + 524FA62B2BCAF2CF00133747 /* AlloFlashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlloFlashView.swift; sourceTree = ""; }; + 524FA62F2BCBF4C300133747 /* tt_chocolates_light.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = tt_chocolates_light.otf; sourceTree = ""; }; + 524FA6302BCBF4C300133747 /* tt_chocolates_extralight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = tt_chocolates_extralight.otf; sourceTree = ""; }; + 524FA6312BCBF4C300133747 /* tt_chocolates_regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = tt_chocolates_regular.otf; sourceTree = ""; }; + 524FA6332BCBF4C300133747 /* tt_chocolates_demibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = tt_chocolates_demibold.otf; sourceTree = ""; }; + 524FA6362BCBF4C300133747 /* tt_chocolates_extrabold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = tt_chocolates_extrabold.otf; sourceTree = ""; }; + 524FA6372BCBF4C300133747 /* tt_chocolates_bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = tt_chocolates_bold.otf; sourceTree = ""; }; + 524FA63B2BCBF4C300133747 /* tt_chocolates_medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = tt_chocolates_medium.otf; sourceTree = ""; }; + 524FA64A2BCBF78200133747 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 524FA64C2BCBFA3000133747 /* TextModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextModifier.swift; sourceTree = ""; }; + 524FA64E2BCC0AA100133747 /* OfferDetailsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferDetailsScreen.swift; sourceTree = ""; }; + 524FA6502BCC115B00133747 /* OffererUserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OffererUserView.swift; sourceTree = ""; }; + 524FA6522BCC326500133747 /* ShareView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareView.swift; sourceTree = ""; }; + 524FA6542BCC339A00133747 /* OfferDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferDetailsView.swift; sourceTree = ""; }; + 524FA6562BCC34E800133747 /* OfferSocialView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferSocialView.swift; sourceTree = ""; }; + 525ED7332BCD257C00FE6109 /* AvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarView.swift; sourceTree = ""; }; + 52B222012BD1492600B55575 /* ShowFullPictureScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowFullPictureScreen.swift; sourceTree = ""; }; + 52B222102BD1631600B55575 /* NotFoundScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotFoundScreen.swift; sourceTree = ""; }; + 52B222122BD16DC800B55575 /* OfferDetailsBodyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferDetailsBodyView.swift; sourceTree = ""; }; + 52B222162BD1737500B55575 /* Extension+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extension+View.swift"; sourceTree = ""; }; + 52B222182BD173FF00B55575 /* OffererUserRatingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OffererUserRatingView.swift; sourceTree = ""; }; + 52B2221A2BD1749E00B55575 /* OffererUserInfos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OffererUserInfos.swift; sourceTree = ""; }; + 52B2221C2BD1756100B55575 /* OffererUserProStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OffererUserProStatusView.swift; sourceTree = ""; }; + 52B2221E2BD175E300B55575 /* OffererUserGallery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OffererUserGallery.swift; sourceTree = ""; }; + 52B222222BD1782700B55575 /* OfferHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferHeaderView.swift; sourceTree = ""; }; + 52B222242BD178D000B55575 /* OfferBodyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferBodyView.swift; sourceTree = ""; }; + 52B222282BD17A6300B55575 /* Offer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Offer.swift; sourceTree = ""; }; + 52B2222A2BD17A7F00B55575 /* Relationships.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Relationships.swift; sourceTree = ""; }; + 52B2222C2BD17A9100B55575 /* Leaseholder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Leaseholder.swift; sourceTree = ""; }; + 52B2222E2BD17AA100B55575 /* Social.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Social.swift; sourceTree = ""; }; + 52B222302BD17ACB00B55575 /* OfferPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferPicture.swift; sourceTree = ""; }; + 52B222322BD17ADC00B55575 /* OfferPictureUrls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferPictureUrls.swift; sourceTree = ""; }; + 52B222342BD17AEB00B55575 /* OfferersUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferersUser.swift; sourceTree = ""; }; + 52B222362BD17B0100B55575 /* OfferersUserMeta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferersUserMeta.swift; sourceTree = ""; }; + 52B222382BD17B1200B55575 /* GalleryPicture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryPicture.swift; sourceTree = ""; }; + 52B2223A2BD17BD100B55575 /* OfferDetailsAwnserCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferDetailsAwnserCountView.swift; sourceTree = ""; }; + 52B2223E2BD17D5800B55575 /* OfferDetailsGalleryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferDetailsGalleryView.swift; sourceTree = ""; }; + 52B222402BD17DF100B55575 /* OfferDetailsLeaseholderInfosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferDetailsLeaseholderInfosView.swift; sourceTree = ""; }; + 52B222422BD1864100B55575 /* OfferDetailsMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferDetailsMapView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -26,6 +122,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 524FA62A2BCAEC0B00133747 /* CachedAsyncImage in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -51,8 +148,17 @@ 524FA5FE2BCACDCE00133747 /* AlloVictor */ = { isa = PBXGroup; children = ( + 524FA64A2BCBF78200133747 /* Info.plist */, + 52B222152BD1735F00B55575 /* Extensions */, + 52B222272BD17A5000B55575 /* Models */, + 524FA6192BCAD03600133747 /* DTO */, + 524FA6182BCAD02E00133747 /* Screens */, + 524FA6172BCAD02600133747 /* Utils */, + 524FA6162BCAD01E00133747 /* Views */, + 524FA6152BCAD01700133747 /* ViewModels */, + 524FA60D2BCACE9400133747 /* Resources */, + 524FA6242BCAD58400133747 /* AppState.swift */, 524FA5FF2BCACDCE00133747 /* AlloVictorApp.swift */, - 524FA6012BCACDCE00133747 /* ContentView.swift */, 524FA6032BCACDCF00133747 /* Assets.xcassets */, 524FA6052BCACDCF00133747 /* Preview Content */, ); @@ -67,6 +173,157 @@ path = "Preview Content"; sourceTree = ""; }; + 524FA60D2BCACE9400133747 /* Resources */ = { + isa = PBXGroup; + children = ( + 524FA62D2BCBF4AD00133747 /* Fonts */, + 524FA60E2BCACF0500133747 /* Screen1.json */, + 524FA6102BCACF3A00133747 /* Screen2.json */, + ); + path = Resources; + sourceTree = ""; + }; + 524FA6152BCAD01700133747 /* ViewModels */ = { + isa = PBXGroup; + children = ( + 524FA6222BCAD29000133747 /* AlloVictorViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; + 524FA6162BCAD01E00133747 /* Views */ = { + isa = PBXGroup; + children = ( + 52B222142BD16E5200B55575 /* Components */, + 524FA64B2BCBFA1900133747 /* Modifiers */, + 524FA62B2BCAF2CF00133747 /* AlloFlashView.swift */, + 524FA6262BCAE1C500133747 /* OfferListView.swift */, + 524FA6542BCC339A00133747 /* OfferDetailsView.swift */, + 524FA6502BCC115B00133747 /* OffererUserView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 524FA6172BCAD02600133747 /* Utils */ = { + isa = PBXGroup; + children = ( + 524FA61A2BCAD04B00133747 /* Constants.swift */, + 524FA6202BCAD22D00133747 /* HTTPClient.swift */, + ); + path = Utils; + sourceTree = ""; + }; + 524FA6182BCAD02E00133747 /* Screens */ = { + isa = PBXGroup; + children = ( + 52B222102BD1631600B55575 /* NotFoundScreen.swift */, + 524FA64E2BCC0AA100133747 /* OfferDetailsScreen.swift */, + 524FA6012BCACDCE00133747 /* OffersListScreen.swift */, + 52B222012BD1492600B55575 /* ShowFullPictureScreen.swift */, + ); + path = Screens; + sourceTree = ""; + }; + 524FA6192BCAD03600133747 /* DTO */ = { + isa = PBXGroup; + children = ( + 524FA61E2BCAD0FD00133747 /* OfferDetailsResponseDTO.swift */, + 524FA61C2BCAD0F100133747 /* OfferListResponseDTO.swift */, + ); + path = DTO; + sourceTree = ""; + }; + 524FA62D2BCBF4AD00133747 /* Fonts */ = { + isa = PBXGroup; + children = ( + 524FA6372BCBF4C300133747 /* tt_chocolates_bold.otf */, + 524FA6332BCBF4C300133747 /* tt_chocolates_demibold.otf */, + 524FA6362BCBF4C300133747 /* tt_chocolates_extrabold.otf */, + 524FA6302BCBF4C300133747 /* tt_chocolates_extralight.otf */, + 524FA62F2BCBF4C300133747 /* tt_chocolates_light.otf */, + 524FA63B2BCBF4C300133747 /* tt_chocolates_medium.otf */, + 524FA6312BCBF4C300133747 /* tt_chocolates_regular.otf */, + ); + path = Fonts; + sourceTree = ""; + }; + 524FA64B2BCBFA1900133747 /* Modifiers */ = { + isa = PBXGroup; + children = ( + 524FA64C2BCBFA3000133747 /* TextModifier.swift */, + ); + path = Modifiers; + sourceTree = ""; + }; + 52B222142BD16E5200B55575 /* Components */ = { + isa = PBXGroup; + children = ( + 52B222212BD1780F00B55575 /* Offer */, + 52B222262BD17A1A00B55575 /* OfferDetails */, + 52B222202BD1766E00B55575 /* OffererUser */, + 525ED7332BCD257C00FE6109 /* AvatarView.swift */, + 524FA6522BCC326500133747 /* ShareView.swift */, + ); + path = Components; + sourceTree = ""; + }; + 52B222152BD1735F00B55575 /* Extensions */ = { + isa = PBXGroup; + children = ( + 52B222162BD1737500B55575 /* Extension+View.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 52B222202BD1766E00B55575 /* OffererUser */ = { + isa = PBXGroup; + children = ( + 52B2221E2BD175E300B55575 /* OffererUserGallery.swift */, + 52B2221A2BD1749E00B55575 /* OffererUserInfos.swift */, + 52B2221C2BD1756100B55575 /* OffererUserProStatusView.swift */, + 52B222182BD173FF00B55575 /* OffererUserRatingView.swift */, + ); + path = OffererUser; + sourceTree = ""; + }; + 52B222212BD1780F00B55575 /* Offer */ = { + isa = PBXGroup; + children = ( + 52B222242BD178D000B55575 /* OfferBodyView.swift */, + 52B222222BD1782700B55575 /* OfferHeaderView.swift */, + 524FA6562BCC34E800133747 /* OfferSocialView.swift */, + ); + path = Offer; + sourceTree = ""; + }; + 52B222262BD17A1A00B55575 /* OfferDetails */ = { + isa = PBXGroup; + children = ( + 52B222122BD16DC800B55575 /* OfferDetailsBodyView.swift */, + 52B2223A2BD17BD100B55575 /* OfferDetailsAwnserCountView.swift */, + 52B2223E2BD17D5800B55575 /* OfferDetailsGalleryView.swift */, + 52B222402BD17DF100B55575 /* OfferDetailsLeaseholderInfosView.swift */, + 52B222422BD1864100B55575 /* OfferDetailsMapView.swift */, + ); + path = OfferDetails; + sourceTree = ""; + }; + 52B222272BD17A5000B55575 /* Models */ = { + isa = PBXGroup; + children = ( + 52B222382BD17B1200B55575 /* GalleryPicture.swift */, + 52B2222C2BD17A9100B55575 /* Leaseholder.swift */, + 52B222282BD17A6300B55575 /* Offer.swift */, + 52B222342BD17AEB00B55575 /* OfferersUser.swift */, + 52B222362BD17B0100B55575 /* OfferersUserMeta.swift */, + 52B222302BD17ACB00B55575 /* OfferPicture.swift */, + 52B222322BD17ADC00B55575 /* OfferPictureUrls.swift */, + 52B2222A2BD17A7F00B55575 /* Relationships.swift */, + 52B2222E2BD17AA100B55575 /* Social.swift */, + ); + path = Models; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -83,6 +340,9 @@ dependencies = ( ); name = AlloVictor; + packageProductDependencies = ( + 524FA6292BCAEC0B00133747 /* CachedAsyncImage */, + ); productName = AlloVictor; productReference = 524FA5FC2BCACDCE00133747 /* AlloVictor.app */; productType = "com.apple.product-type.application"; @@ -111,6 +371,9 @@ Base, ); mainGroup = 524FA5F32BCACDCE00133747; + packageReferences = ( + 524FA6282BCAEC0B00133747 /* XCRemoteSwiftPackageReference "swiftui-cached-async-image" */, + ); productRefGroup = 524FA5FD2BCACDCE00133747 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -125,7 +388,16 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 524FA63E2BCBF4C300133747 /* tt_chocolates_extralight.otf in Resources */, + 524FA60F2BCACF0500133747 /* Screen1.json in Resources */, + 524FA6412BCBF4C300133747 /* tt_chocolates_demibold.otf in Resources */, 524FA6072BCACDCF00133747 /* Preview Assets.xcassets in Resources */, + 524FA6452BCBF4C300133747 /* tt_chocolates_bold.otf in Resources */, + 524FA6492BCBF4C300133747 /* tt_chocolates_medium.otf in Resources */, + 524FA6442BCBF4C300133747 /* tt_chocolates_extrabold.otf in Resources */, + 524FA63D2BCBF4C300133747 /* tt_chocolates_light.otf in Resources */, + 524FA63F2BCBF4C300133747 /* tt_chocolates_regular.otf in Resources */, + 524FA6112BCACF3A00133747 /* Screen2.json in Resources */, 524FA6042BCACDCF00133747 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -137,8 +409,46 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 524FA6022BCACDCE00133747 /* ContentView.swift in Sources */, + 52B222252BD178D000B55575 /* OfferBodyView.swift in Sources */, + 52B222332BD17ADC00B55575 /* OfferPictureUrls.swift in Sources */, + 524FA6022BCACDCE00133747 /* OffersListScreen.swift in Sources */, + 52B222172BD1737500B55575 /* Extension+View.swift in Sources */, + 524FA61F2BCAD0FD00133747 /* OfferDetailsResponseDTO.swift in Sources */, + 52B222432BD1864100B55575 /* OfferDetailsMapView.swift in Sources */, + 52B2221D2BD1756100B55575 /* OffererUserProStatusView.swift in Sources */, + 52B2222B2BD17A7F00B55575 /* Relationships.swift in Sources */, + 52B2221B2BD1749E00B55575 /* OffererUserInfos.swift in Sources */, + 524FA6212BCAD22D00133747 /* HTTPClient.swift in Sources */, + 524FA64F2BCC0AA100133747 /* OfferDetailsScreen.swift in Sources */, + 524FA6272BCAE1C500133747 /* OfferListView.swift in Sources */, + 524FA6252BCAD58400133747 /* AppState.swift in Sources */, + 524FA6512BCC115B00133747 /* OffererUserView.swift in Sources */, + 52B2221F2BD175E300B55575 /* OffererUserGallery.swift in Sources */, + 52B222412BD17DF100B55575 /* OfferDetailsLeaseholderInfosView.swift in Sources */, 524FA6002BCACDCE00133747 /* AlloVictorApp.swift in Sources */, + 524FA6572BCC34E900133747 /* OfferSocialView.swift in Sources */, + 52B2222F2BD17AA100B55575 /* Social.swift in Sources */, + 524FA64D2BCBFA3000133747 /* TextModifier.swift in Sources */, + 52B222352BD17AEB00B55575 /* OfferersUser.swift in Sources */, + 524FA6552BCC339A00133747 /* OfferDetailsView.swift in Sources */, + 52B222192BD173FF00B55575 /* OffererUserRatingView.swift in Sources */, + 52B222392BD17B1200B55575 /* GalleryPicture.swift in Sources */, + 52B2222D2BD17A9100B55575 /* Leaseholder.swift in Sources */, + 52B222232BD1782700B55575 /* OfferHeaderView.swift in Sources */, + 524FA61D2BCAD0F100133747 /* OfferListResponseDTO.swift in Sources */, + 52B2223F2BD17D5800B55575 /* OfferDetailsGalleryView.swift in Sources */, + 52B222132BD16DC800B55575 /* OfferDetailsBodyView.swift in Sources */, + 524FA6532BCC326500133747 /* ShareView.swift in Sources */, + 524FA62C2BCAF2CF00133747 /* AlloFlashView.swift in Sources */, + 52B222292BD17A6300B55575 /* Offer.swift in Sources */, + 52B222022BD1492600B55575 /* ShowFullPictureScreen.swift in Sources */, + 52B222112BD1631600B55575 /* NotFoundScreen.swift in Sources */, + 524FA6232BCAD29000133747 /* AlloVictorViewModel.swift in Sources */, + 52B222372BD17B0100B55575 /* OfferersUserMeta.swift in Sources */, + 52B222312BD17ACB00B55575 /* OfferPicture.swift in Sources */, + 525ED7342BCD257C00FE6109 /* AvatarView.swift in Sources */, + 52B2223B2BD17BD100B55575 /* OfferDetailsAwnserCountView.swift in Sources */, + 524FA61B2BCAD04B00133747 /* Constants.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -275,11 +585,13 @@ DEVELOPMENT_TEAM = WVH3Y23X7X; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = AlloVictor/Info.plist; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UIUserInterfaceStyle = Light; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -304,11 +616,13 @@ DEVELOPMENT_TEAM = WVH3Y23X7X; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = AlloVictor/Info.plist; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UIUserInterfaceStyle = Light; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -344,6 +658,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 524FA6282BCAEC0B00133747 /* XCRemoteSwiftPackageReference "swiftui-cached-async-image" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/lorenzofiamingo/swiftui-cached-async-image"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.1.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 524FA6292BCAEC0B00133747 /* CachedAsyncImage */ = { + isa = XCSwiftPackageProductDependency; + package = 524FA6282BCAEC0B00133747 /* XCRemoteSwiftPackageReference "swiftui-cached-async-image" */; + productName = CachedAsyncImage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 524FA5F42BCACDCE00133747 /* Project object */; } diff --git a/AlloVictor.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/AlloVictor.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..c138097 --- /dev/null +++ b/AlloVictor.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "swiftui-cached-async-image", + "kind" : "remoteSourceControl", + "location" : "https://github.com/lorenzofiamingo/swiftui-cached-async-image", + "state" : { + "revision" : "467a3d17479887943ab917a379e62bbaff60ac8a", + "version" : "2.1.1" + } + } + ], + "version" : 2 +} diff --git a/AlloVictor.xcodeproj/xcuserdata/bodinaudvictor.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/AlloVictor.xcodeproj/xcuserdata/bodinaudvictor.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..0d6b43a --- /dev/null +++ b/AlloVictor.xcodeproj/xcuserdata/bodinaudvictor.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/AlloVictor/AlloVictorApp.swift b/AlloVictor/AlloVictorApp.swift index 7f87f02..b890112 100644 --- a/AlloVictor/AlloVictorApp.swift +++ b/AlloVictor/AlloVictorApp.swift @@ -9,9 +9,36 @@ import SwiftUI @main struct AlloVictorApp: App { + + @StateObject private var viewModel = AlloVictorViewModel() + @StateObject private var appState = AppState() + + private func fetchOffers() async { + do { + try await viewModel.getDatas() + } catch { + print(error.localizedDescription) + } + } + var body: some Scene { WindowGroup { - ContentView() + NavigationStack(path: $appState.routes) { + OffersListScreen() + .navigationDestination(for: Route.self) { route in + switch route { + case .offers: + OffersListScreen() + case .detail(let offer): + OfferDetailsScreen(offerDetails: offer) + } + } + } + .task { + await fetchOffers() + } + .environmentObject(viewModel) + .environmentObject(appState) } } } diff --git a/AlloVictor/AppState.swift b/AlloVictor/AppState.swift new file mode 100644 index 0000000..ad4f033 --- /dev/null +++ b/AlloVictor/AppState.swift @@ -0,0 +1,17 @@ +// +// AppState.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import Foundation + +enum Route: Hashable { + case offers + case detail(Offer?) +} + +class AppState: ObservableObject { + @Published var routes: [Route] = [] +} diff --git a/AlloVictor/Assets.xcassets/AppIcon.appiconset/Contents.json b/AlloVictor/Assets.xcassets/AppIcon.appiconset/Contents.json index 13613e3..b3f44eb 100644 --- a/AlloVictor/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/AlloVictor/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,6 +1,7 @@ { "images" : [ { + "filename" : "Icon.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/AlloVictor/Assets.xcassets/AppIcon.appiconset/icon.png b/AlloVictor/Assets.xcassets/AppIcon.appiconset/icon.png new file mode 100644 index 0000000..2ec51e9 Binary files /dev/null and b/AlloVictor/Assets.xcassets/AppIcon.appiconset/icon.png differ diff --git a/AlloVictor/Assets.xcassets/Colors/Contents.json b/AlloVictor/Assets.xcassets/Colors/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/AlloVictor/Assets.xcassets/Colors/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Colors/grape30.colorset/Contents.json b/AlloVictor/Assets.xcassets/Colors/grape30.colorset/Contents.json new file mode 100644 index 0000000..5d718c9 --- /dev/null +++ b/AlloVictor/Assets.xcassets/Colors/grape30.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0xF3", + "green" : "0xCF", + "red" : "0xE6" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0xF3", + "green" : "0xCF", + "red" : "0xE6" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Colors/neutral20.colorset/Contents.json b/AlloVictor/Assets.xcassets/Colors/neutral20.colorset/Contents.json new file mode 100644 index 0000000..63baa93 --- /dev/null +++ b/AlloVictor/Assets.xcassets/Colors/neutral20.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.894", + "green" : "0.843", + "red" : "0.808" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.894", + "green" : "0.843", + "red" : "0.808" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Colors/pillButtonColor.colorset/Contents.json b/AlloVictor/Assets.xcassets/Colors/pillButtonColor.colorset/Contents.json new file mode 100644 index 0000000..d30bafb --- /dev/null +++ b/AlloVictor/Assets.xcassets/Colors/pillButtonColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0x31", + "green" : "0x23", + "red" : "0x18" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0x31", + "green" : "0x23", + "red" : "0x18" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Pictures/Avatar.imageset/Avatar.png b/AlloVictor/Assets.xcassets/Pictures/Avatar.imageset/Avatar.png new file mode 100644 index 0000000..da2a9fa Binary files /dev/null and b/AlloVictor/Assets.xcassets/Pictures/Avatar.imageset/Avatar.png differ diff --git a/AlloVictor/Assets.xcassets/Pictures/Avatar.imageset/Contents.json b/AlloVictor/Assets.xcassets/Pictures/Avatar.imageset/Contents.json new file mode 100644 index 0000000..04c9d3c --- /dev/null +++ b/AlloVictor/Assets.xcassets/Pictures/Avatar.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Avatar.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Pictures/Contents.json b/AlloVictor/Assets.xcassets/Pictures/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/AlloVictor/Assets.xcassets/Pictures/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Pictures/Icon.imageset/Contents.json b/AlloVictor/Assets.xcassets/Pictures/Icon.imageset/Contents.json new file mode 100644 index 0000000..1ffad00 --- /dev/null +++ b/AlloVictor/Assets.xcassets/Pictures/Icon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "icon.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Pictures/Icon.imageset/icon.png b/AlloVictor/Assets.xcassets/Pictures/Icon.imageset/icon.png new file mode 100644 index 0000000..3a9902e Binary files /dev/null and b/AlloVictor/Assets.xcassets/Pictures/Icon.imageset/icon.png differ diff --git a/AlloVictor/Assets.xcassets/Pictures/SimpleLogo.imageset/Contents.json b/AlloVictor/Assets.xcassets/Pictures/SimpleLogo.imageset/Contents.json new file mode 100644 index 0000000..4b401e0 --- /dev/null +++ b/AlloVictor/Assets.xcassets/Pictures/SimpleLogo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Logo Victor2.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Pictures/SimpleLogo.imageset/Logo Victor2.png b/AlloVictor/Assets.xcassets/Pictures/SimpleLogo.imageset/Logo Victor2.png new file mode 100644 index 0000000..1493210 Binary files /dev/null and b/AlloVictor/Assets.xcassets/Pictures/SimpleLogo.imageset/Logo Victor2.png differ diff --git a/AlloVictor/Assets.xcassets/Pictures/oups.imageset/Contents.json b/AlloVictor/Assets.xcassets/Pictures/oups.imageset/Contents.json new file mode 100644 index 0000000..2286b77 --- /dev/null +++ b/AlloVictor/Assets.xcassets/Pictures/oups.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "oups.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/AlloVictor/Assets.xcassets/Pictures/oups.imageset/oups.svg b/AlloVictor/Assets.xcassets/Pictures/oups.imageset/oups.svg new file mode 100644 index 0000000..ac08126 --- /dev/null +++ b/AlloVictor/Assets.xcassets/Pictures/oups.imageset/oups.svg @@ -0,0 +1,59 @@ + + + + 6F323CAA-B7A5-4B13-98A5-A3266E99B020 + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AlloVictor/ContentView.swift b/AlloVictor/ContentView.swift deleted file mode 100644 index 0b0656d..0000000 --- a/AlloVictor/ContentView.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ContentView.swift -// AlloVictor -// -// Created by Bodinaud Victor on 13/04/2024. -// - -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) - Text("Hello, world!") - } - .padding() - } -} - -#Preview { - ContentView() -} diff --git a/AlloVictor/DTO/OfferDetailsResponseDTO.swift b/AlloVictor/DTO/OfferDetailsResponseDTO.swift new file mode 100644 index 0000000..1f20d4d --- /dev/null +++ b/AlloVictor/DTO/OfferDetailsResponseDTO.swift @@ -0,0 +1,13 @@ +// +// OfferDetailsResponseDTO.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import Foundation + +struct OfferDetailsResponseDTO: Codable { + let format: String + let data: Offer +} diff --git a/AlloVictor/DTO/OfferListResponseDTO.swift b/AlloVictor/DTO/OfferListResponseDTO.swift new file mode 100644 index 0000000..67e7e1e --- /dev/null +++ b/AlloVictor/DTO/OfferListResponseDTO.swift @@ -0,0 +1,13 @@ +// +// OfferListResponseDTO.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import Foundation + +struct OfferListResponseDTO: Codable { + let format: String + let data: [Offer] +} diff --git a/AlloVictor/Extensions/Extension+View.swift b/AlloVictor/Extensions/Extension+View.swift new file mode 100644 index 0000000..21214cb --- /dev/null +++ b/AlloVictor/Extensions/Extension+View.swift @@ -0,0 +1,16 @@ +// +// Extension+View.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI + +extension View { + public func addBorder(_ content: S, width: CGFloat = 1, cornerRadius: CGFloat) -> some View where S : ShapeStyle { + let roundedRect = RoundedRectangle(cornerRadius: cornerRadius) + return clipShape(roundedRect) + .overlay(roundedRect.strokeBorder(content, lineWidth: width)) + } + } diff --git a/AlloVictor/Info.plist b/AlloVictor/Info.plist new file mode 100644 index 0000000..b67325d --- /dev/null +++ b/AlloVictor/Info.plist @@ -0,0 +1,16 @@ + + + + + UIAppFonts + + tt_chocolates_extralight.otf + tt_chocolates_light.otf + tt_chocolates_medium.otf + tt_chocolates_regular.otf + tt_chocolates_demibold.otf + tt_chocolates_bold.otf + tt_chocolates_extrabold.otf + + + diff --git a/AlloVictor/Models/GalleryPicture.swift b/AlloVictor/Models/GalleryPicture.swift new file mode 100644 index 0000000..3f1d904 --- /dev/null +++ b/AlloVictor/Models/GalleryPicture.swift @@ -0,0 +1,20 @@ +// +// GalleryPicture.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +struct GalleryPicture: Codable, Identifiable { + let id: Int + let imageLarge: String + let imageSmall: String + + enum CodingKeys: String, CodingKey { + case id + case imageLarge + case imageSmall + } +} diff --git a/AlloVictor/Models/Leaseholder.swift b/AlloVictor/Models/Leaseholder.swift new file mode 100644 index 0000000..6d3259e --- /dev/null +++ b/AlloVictor/Models/Leaseholder.swift @@ -0,0 +1,22 @@ +// +// Leaseholder.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +struct Leaseholder: Codable, Identifiable { + let id: Int + let displayName: String + let avatarUrl: String + let userRatings: Int + + enum CodingKeys: String, CodingKey { + case id + case displayName + case avatarUrl + case userRatings + } +} diff --git a/AlloVictor/Models/Offer.swift b/AlloVictor/Models/Offer.swift new file mode 100644 index 0000000..c6dae81 --- /dev/null +++ b/AlloVictor/Models/Offer.swift @@ -0,0 +1,55 @@ +// +// Offer.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +enum CardType: String, Codable { + case alloFlash = "card_blog_alloflash" + case publicSearch = "card_search_public" +} + +struct Offer: Codable, Identifiable, Hashable { + var id: Int + let latitude: Double? + let longitude: Double? + let cardType: CardType? + let desc: String? + let objectName: String? + let sectionBackgroundImage: String? + let relationships: Relationships + let publishedAtFormatted: String? + let searchPictureUrl: String? + let locationFormatted: String? + let distanceFormatted: String? + let budgetFormatted: String? + let pictures: [OfferPicture]? + + enum CodingKeys: String, CodingKey { + case id = "refId" + case latitude + case longitude + case cardType + case desc = "description" + case objectName + case sectionBackgroundImage + case relationships + case publishedAtFormatted + case searchPictureUrl + case locationFormatted + case distanceFormatted + case budgetFormatted + case pictures + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(id) + } + + public static func == (lhs: Offer, rhs: Offer) -> Bool { + return lhs.id == rhs.id + } +} diff --git a/AlloVictor/Models/OfferPicture.swift b/AlloVictor/Models/OfferPicture.swift new file mode 100644 index 0000000..9c1580d --- /dev/null +++ b/AlloVictor/Models/OfferPicture.swift @@ -0,0 +1,18 @@ +// +// OfferPicture.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +struct OfferPicture: Codable, Identifiable { + let id: Int + let pictureUrls: OfferPictureUrls + + enum CodingKeys: String, CodingKey { + case id + case pictureUrls + } +} diff --git a/AlloVictor/Models/OfferPictureUrls.swift b/AlloVictor/Models/OfferPictureUrls.swift new file mode 100644 index 0000000..fc20262 --- /dev/null +++ b/AlloVictor/Models/OfferPictureUrls.swift @@ -0,0 +1,13 @@ +// +// OfferPictureUrls.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +struct OfferPictureUrls: Codable { + let large: String + let small: String +} diff --git a/AlloVictor/Models/OfferersUser.swift b/AlloVictor/Models/OfferersUser.swift new file mode 100644 index 0000000..46d1e92 --- /dev/null +++ b/AlloVictor/Models/OfferersUser.swift @@ -0,0 +1,42 @@ +// +// OfferersUser.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +struct OfferersUser: Codable, Identifiable { + let id: Int + let displayName: String + let firstName: String + let avatarUrl: String + let headline: String + let reviewsCount: Int + let averageRating: Double + let onlineLatestActivityAt: Int + let onlineLatestActivityAtFormatted: String + let distanceFormatted: String + let locationFormatted: String + let isIndependent: Bool + let relationships: Relationships + let meta: OfferersUserMeta + + enum CodingKeys: String, CodingKey { + case id = "refId" + case displayName + case firstName + case headline + case avatarUrl + case reviewsCount + case averageRating + case onlineLatestActivityAt + case onlineLatestActivityAtFormatted + case distanceFormatted + case locationFormatted + case isIndependent + case relationships + case meta + } +} diff --git a/AlloVictor/Models/OfferersUserMeta.swift b/AlloVictor/Models/OfferersUserMeta.swift new file mode 100644 index 0000000..c53dd0b --- /dev/null +++ b/AlloVictor/Models/OfferersUserMeta.swift @@ -0,0 +1,16 @@ +// +// OfferersUserMeta.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +struct OfferersUserMeta: Codable { + let answeredAtFormatted: String + + enum CodingKeys: String, CodingKey { + case answeredAtFormatted + } +} diff --git a/AlloVictor/Models/Relationships.swift b/AlloVictor/Models/Relationships.swift new file mode 100644 index 0000000..ca1f990 --- /dev/null +++ b/AlloVictor/Models/Relationships.swift @@ -0,0 +1,22 @@ +// +// Relationships.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +struct Relationships: Codable { + let leaseholder: Leaseholder? + let social: Social? + let offerersUsers: [OfferersUser]? + let galleryPictures: [GalleryPicture]? + + enum CodingKeys: String, CodingKey { + case leaseholder + case social + case offerersUsers + case galleryPictures + } +} diff --git a/AlloVictor/Models/Social.swift b/AlloVictor/Models/Social.swift new file mode 100644 index 0000000..fca5900 --- /dev/null +++ b/AlloVictor/Models/Social.swift @@ -0,0 +1,20 @@ +// +// Social.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import Foundation + +struct Social: Codable { + let likesCount: Int + let answerersCount: Int? + let shareLink: String? + + enum CodingKeys: String, CodingKey { + case likesCount + case answerersCount + case shareLink + } +} diff --git a/AlloVictor/Resources/Fonts/tt_chocolates_bold.otf b/AlloVictor/Resources/Fonts/tt_chocolates_bold.otf new file mode 100644 index 0000000..d963e86 Binary files /dev/null and b/AlloVictor/Resources/Fonts/tt_chocolates_bold.otf differ diff --git a/AlloVictor/Resources/Fonts/tt_chocolates_demibold.otf b/AlloVictor/Resources/Fonts/tt_chocolates_demibold.otf new file mode 100644 index 0000000..7938280 Binary files /dev/null and b/AlloVictor/Resources/Fonts/tt_chocolates_demibold.otf differ diff --git a/AlloVictor/Resources/Fonts/tt_chocolates_extrabold.otf b/AlloVictor/Resources/Fonts/tt_chocolates_extrabold.otf new file mode 100644 index 0000000..7493ce3 Binary files /dev/null and b/AlloVictor/Resources/Fonts/tt_chocolates_extrabold.otf differ diff --git a/AlloVictor/Resources/Fonts/tt_chocolates_extralight.otf b/AlloVictor/Resources/Fonts/tt_chocolates_extralight.otf new file mode 100644 index 0000000..6373fb5 Binary files /dev/null and b/AlloVictor/Resources/Fonts/tt_chocolates_extralight.otf differ diff --git a/AlloVictor/Resources/Fonts/tt_chocolates_light.otf b/AlloVictor/Resources/Fonts/tt_chocolates_light.otf new file mode 100644 index 0000000..dd8d713 Binary files /dev/null and b/AlloVictor/Resources/Fonts/tt_chocolates_light.otf differ diff --git a/AlloVictor/Resources/Fonts/tt_chocolates_medium.otf b/AlloVictor/Resources/Fonts/tt_chocolates_medium.otf new file mode 100644 index 0000000..5cc79ef Binary files /dev/null and b/AlloVictor/Resources/Fonts/tt_chocolates_medium.otf differ diff --git a/AlloVictor/Resources/Fonts/tt_chocolates_regular.otf b/AlloVictor/Resources/Fonts/tt_chocolates_regular.otf new file mode 100644 index 0000000..a26ed01 Binary files /dev/null and b/AlloVictor/Resources/Fonts/tt_chocolates_regular.otf differ diff --git a/AlloVictor/Resources/Screen1.json b/AlloVictor/Resources/Screen1.json new file mode 100644 index 0000000..dd50029 --- /dev/null +++ b/AlloVictor/Resources/Screen1.json @@ -0,0 +1,495 @@ +{ + "format": "json", + "data": [ + { + "links": { + "self": "https://www.allovoisins.com/s/8734007" + }, + "budget": 0, + "ref_id": 8734007, + "datetime": "2023-12-15 15:43:08", + "duration": 1, + "end_date": null, + "latitude": 47.2132, + "only_pro": false, + "ref_type": "search", + "card_type": "card_search_public", + "city_name": "Nantes", + "longitude": -1.55524, + "object_id": 5392, + "start_date": null, + "category_id": 124, + "description": "Bonjour, Je cherche quelqu'un en mesure de fixer une plainte / moulure arrachée sur un pan de mon mur suite à la chute d'un miroir. Merci par avance Lucie", + "object_name": "Bricolage - Petits travaux", + "ref_type_id": 101, + "search_type": 4, + "card_type_id": 301, + "district_name": "Gloriette-Feydeau", + "duration_type": 3, + "relationships": { + "moment": null, + "social": { + "type": "social", + "answerers_count": 4, + "likes_count": 1, + "shares_count": 0, + "recommendations_count": 0, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/s/8734007?utm_source=product_transactionnel&utm_medium=share&utm_campaign=search_details", + "comments_count": null, + "comments": null + }, + "leaseholder": { + "id": 5539939, + "type": "user", + "is_pro": false, + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar9.png", + "is_favorite": false, + "is_new_user": true, + "display_name": "Lucie A.", + "user_ratings": 0, + "part_pro_status": 0, + "user_ratings_count": 0 + } + }, + "budget_formatted": "À convenir", + "duration_formatted": "", + "location_formatted": "Nantes (Gloriette-Feydeau)", + "search_picture_url": null, + "search_picture_urls": [], + "is_category_regulated": false, + "search_pictures_count": 0, + "published_at_formatted": "postée le 15 déc.", + "published_at_formatted_year": "demande postée le 15 déc. 2023", + "distance_formatted": "600 m" + }, + { + "links": { + "self": "https://www.allovoisins.com/s/8731481" + }, + "budget": 0, + "ref_id": 8731481, + "datetime": "2023-12-14 23:13:12", + "duration": 1, + "end_date": null, + "latitude": 47.2102, + "only_pro": false, + "ref_type": "search", + "card_type": "card_search_public", + "city_name": "Nantes", + "longitude": -1.5498, + "object_id": 5392, + "start_date": null, + "category_id": 124, + "description": "Bonjour, Je cherche à changer le plan de travail de ma cuisine ( découpe évier et plaque électrique) plus pose 1meuble haut sur carquefou", + "object_name": "Bricolage - Petits travaux", + "ref_type_id": 101, + "search_type": 4, + "card_type_id": 301, + "district_name": "Madeleine", + "duration_type": 3, + "relationships": { + "moment": null, + "social": { + "type": "social", + "answerers_count": 9, + "likes_count": 2, + "shares_count": 0, + "recommendations_count": 0, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/s/8731481?utm_source=product_transactionnel&utm_medium=share&utm_campaign=search_details", + "comments_count": null, + "comments": null + }, + "leaseholder": { + "id": 4730931, + "type": "user", + "is_pro": false, + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar1.png", + "is_favorite": false, + "is_new_user": false, + "display_name": "Franck R.", + "user_ratings": 0, + "part_pro_status": 0, + "user_ratings_count": 0 + } + }, + "budget_formatted": "À convenir", + "duration_formatted": "", + "location_formatted": "Nantes (Madeleine)", + "search_picture_url": null, + "search_picture_urls": [], + "is_category_regulated": false, + "search_pictures_count": 0, + "published_at_formatted": "postée le 14 déc.", + "published_at_formatted_year": "demande postée le 14 déc. 2023", + "distance_formatted": "500 m" + }, + { + "card_type_id": 394, + "ref_type_id": 110, + "ref_id": 658, + "tags": { + "newsfeed_all": 0, + "perimetre_all": 0, + "perimetre_pro_ap": 1, + "perimetre_part_ap": 0, + "perimetre_pro_non_abonne": 0, + "perimetre_part_non_abonne": 0 + }, + "datetime": "2022-12-12 12:00:16", + "ref_type": "blog", + "card_type": "card_blog_alloflash", + "section_link": "https://www.allovoisins.com/espace-pro", + "section_type": "section_image", + "date_formatted": "Il y a 12 mois", + "is_commentable": false, + "category_formatted": "AlloFlash", + "section_background_image": "https://blog.allovoisins.com/wp-content/uploads/2022/12/alloflash-logiciel-pro.png", + "relationships": { + "social": { + "type": "social", + "answerers_count": null, + "likes_count": 129, + "shares_count": 0, + "recommendations_count": null, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/article/658-?utm_source=product_transactionnel&utm_medium=share&utm_campaign=blog", + "comments_count": 0, + "comments": null + } + } + }, + { + "links": { + "self": "https://www.allovoisins.com/s/8702434" + }, + "budget": 30, + "ref_id": 8702434, + "datetime": "2023-12-08 21:08:10", + "duration": 1, + "end_date": null, + "latitude": 47.2171, + "only_pro": false, + "ref_type": "search", + "card_type": "card_search_public", + "city_name": "Nantes", + "longitude": -1.54593, + "object_id": 5392, + "start_date": null, + "category_id": 124, + "description": "Bonjour, Je dois installer un spot extérieur au dessus de mon magasin en centre ville de Nantes et je cherche quelqu'un avec une échelle d'au moins 5 mètre qui puissent me le fixer en hauteur (le branchement sera déjà fait). C'est l'histoire de quelques minutes . Merci", + "object_name": "Bricolage - Petits travaux", + "ref_type_id": 101, + "search_type": 4, + "card_type_id": 301, + "district_name": "Richebourg-Saint-Clément", + "duration_type": 1, + "relationships": { + "moment": null, + "social": { + "type": "social", + "answerers_count": 2, + "likes_count": 0, + "shares_count": 0, + "recommendations_count": 0, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/s/8702434?utm_source=product_transactionnel&utm_medium=share&utm_campaign=search_details", + "comments_count": null, + "comments": null + }, + "leaseholder": { + "id": 3230135, + "type": "user", + "is_pro": false, + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar5.png", + "is_favorite": false, + "is_new_user": false, + "display_name": "Christophe", + "user_ratings": 0, + "part_pro_status": 0, + "user_ratings_count": 0 + } + }, + "budget_formatted": "30€ / heure", + "duration_formatted": "", + "location_formatted": "Nantes (Richebourg-Saint-Clément)", + "search_picture_url": null, + "search_picture_urls": [], + "is_category_regulated": false, + "search_pictures_count": 0, + "published_at_formatted": "postée le 08 déc.", + "published_at_formatted_year": "demande postée le 08 déc. 2023", + "distance_formatted": "400 m" + }, + { + "links": { + "self": "https://www.allovoisins.com/s/8700262" + }, + "budget": 0, + "ref_id": 8700262, + "datetime": "2023-12-08 12:55:10", + "duration": 1, + "end_date": null, + "latitude": 47.2146, + "only_pro": false, + "ref_type": "search", + "card_type": "card_search_public", + "city_name": "Nantes", + "longitude": -1.55719, + "object_id": 5392, + "start_date": null, + "category_id": 124, + "description": "Bonjour, J'ai besoin d'une personne bricoleuse multi services pour des finitions dans un appartement dans le centre ville de Nantes", + "object_name": "Bricolage - Petits travaux", + "ref_type_id": 101, + "search_type": 4, + "card_type_id": 301, + "district_name": "Graslin-Commerce", + "duration_type": 3, + "relationships": { + "moment": null, + "social": { + "type": "social", + "answerers_count": 14, + "likes_count": 0, + "shares_count": 0, + "recommendations_count": 0, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/s/8700262?utm_source=product_transactionnel&utm_medium=share&utm_campaign=search_details", + "comments_count": null, + "comments": null + }, + "leaseholder": { + "id": 5063804, + "type": "user", + "is_pro": false, + "avatar_url": "https://static.allovoisins.com/uploads/u/avatars/3/2/b/32bb61f4ba_5063804_m.jpg", + "is_favorite": false, + "is_new_user": false, + "display_name": "Rolland T.", + "user_ratings": 5, + "part_pro_status": 0, + "user_ratings_count": 1 + } + }, + "budget_formatted": "À convenir", + "duration_formatted": "", + "location_formatted": "Nantes (Graslin-Commerce)", + "search_picture_url": null, + "search_picture_urls": [], + "is_category_regulated": false, + "search_pictures_count": 0, + "published_at_formatted": "postée le 08 déc.", + "published_at_formatted_year": "demande postée le 08 déc. 2023", + "distance_formatted": "700 m" + }, + { + "links": { + "self": "https://www.allovoisins.com/s/8695834" + }, + "budget": 0, + "ref_id": 8695834, + "datetime": "2023-12-07 12:31:11", + "duration": 1, + "end_date": null, + "latitude": 47.2125, + "only_pro": false, + "ref_type": "search", + "card_type": "card_search_public", + "city_name": "Nantes", + "longitude": -1.55933, + "object_id": 5392, + "start_date": null, + "category_id": 124, + "description": "Bonjour, je souhaite que quelqu'un m'installe un chien de porte sur ma porte d'entrée en appartement. Il faut l'a redecouper sur quelques centimètres :)", + "object_name": "Bricolage - Petits travaux", + "ref_type_id": 101, + "search_type": 4, + "card_type_id": 301, + "district_name": "Graslin-Commerce", + "duration_type": 3, + "relationships": { + "moment": null, + "social": { + "type": "social", + "answerers_count": 5, + "likes_count": 1, + "shares_count": 0, + "recommendations_count": 0, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/s/8695834?utm_source=product_transactionnel&utm_medium=share&utm_campaign=search_details", + "comments_count": null, + "comments": null + }, + "leaseholder": { + "id": 5046469, + "type": "user", + "is_pro": false, + "avatar_url": "https://static.allovoisins.com/uploads/u/avatars/4/b/4/4b4d29b6a4_5046469_m.jpg", + "is_favorite": false, + "is_new_user": false, + "display_name": "Bun N.", + "user_ratings": 5, + "part_pro_status": 0, + "user_ratings_count": 2 + } + }, + "budget_formatted": "À convenir", + "duration_formatted": "", + "location_formatted": "Nantes (Graslin-Commerce)", + "search_picture_url": null, + "search_picture_urls": [], + "is_category_regulated": false, + "search_pictures_count": 0, + "published_at_formatted": "postée le 07 déc.", + "published_at_formatted_year": "demande postée le 07 déc. 2023", + "distance_formatted": "900 m" + }, + { + "links": { + "self": "https://www.allovoisins.com/s/8685235" + }, + "budget": 0, + "ref_id": 8685235, + "datetime": "2023-12-05 09:01:03", + "duration": 1, + "end_date": null, + "latitude": 47.2094, + "only_pro": false, + "ref_type": "search", + "card_type": "card_search_public", + "city_name": "Nantes", + "longitude": -1.55641, + "object_id": 5392, + "start_date": null, + "category_id": 124, + "description": "Bonjour, je cherche quelqu'un pour poser un meuble de cuisine mural. C'est sur du placo et du béton derrière. Par contre dans le colis il n'y avait pas les vis pour la pose. Si quelqu'un peut le faire n'hésitez pas m'écrire. Merci.", + "object_name": "Bricolage - Petits travaux", + "ref_type_id": 101, + "search_type": 4, + "card_type_id": 301, + "district_name": "Gloriette-Feydeau", + "duration_type": 3, + "relationships": { + "moment": null, + "social": { + "type": "social", + "answerers_count": 9, + "likes_count": 3, + "shares_count": 0, + "recommendations_count": 0, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/s/8685235?utm_source=product_transactionnel&utm_medium=share&utm_campaign=search_details", + "comments_count": null, + "comments": null + }, + "leaseholder": { + "id": 3613005, + "type": "user", + "is_pro": false, + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar5.png", + "is_favorite": false, + "is_new_user": false, + "display_name": "Céline", + "user_ratings": 0, + "part_pro_status": 0, + "user_ratings_count": 0 + } + }, + "budget_formatted": "À convenir", + "duration_formatted": "", + "location_formatted": "Nantes (Gloriette-Feydeau)", + "search_picture_url": null, + "search_picture_urls": [], + "is_category_regulated": false, + "search_pictures_count": 0, + "published_at_formatted": "postée le 05 déc.", + "published_at_formatted_year": "demande postée le 05 déc. 2023", + "distance_formatted": "900 m" + }, + { + "links": { + "self": "https://www.allovoisins.com/s/8654097" + }, + "budget": 0, + "ref_id": 8654097, + "datetime": "2023-11-28 14:56:02", + "duration": 1, + "end_date": null, + "latitude": 47.2182, + "only_pro": false, + "ref_type": "search", + "card_type": "card_search_public", + "city_name": "Nantes", + "longitude": -1.55947, + "object_id": 5392, + "start_date": null, + "category_id": 124, + "description": "Bonjour, Je cherche une personne qui pourrait me monter cette écran avec caméra intégrée à l'arrière du véhicule je suis livre aujourd'hui , je vie prêt de leclerc paridise à Nantes. Au plaisir de vous lire Merci. Cordialement Sal", + "object_name": "Bricolage - Petits travaux", + "ref_type_id": 101, + "search_type": 4, + "card_type_id": 301, + "district_name": "Bretagne", + "duration_type": 3, + "relationships": { + "moment": null, + "social": { + "type": "social", + "answerers_count": 2, + "likes_count": 0, + "shares_count": 0, + "recommendations_count": 0, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/s/8654097?utm_source=product_transactionnel&utm_medium=share&utm_campaign=search_details", + "comments_count": null, + "comments": null + }, + "leaseholder": { + "id": 5508536, + "type": "user", + "is_pro": false, + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar6.png", + "is_favorite": false, + "is_new_user": true, + "display_name": "Sam F.", + "user_ratings": 0, + "part_pro_status": 0, + "user_ratings_count": 0 + } + }, + "budget_formatted": "À convenir", + "duration_formatted": "", + "location_formatted": "Nantes (Bretagne)", + "search_picture_url": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_l.jpg", + "search_picture_urls": [ + { + "l": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_l.jpg", + "s": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_l.jpg" + } + ], + "is_category_regulated": false, + "search_pictures_count": 1, + "published_at_formatted": "postée le 28 nov.", + "published_at_formatted_year": "demande postée le 28 nov. 2023", + "distance_formatted": "1000 m" + } + ] +} diff --git a/AlloVictor/Resources/Screen2.json b/AlloVictor/Resources/Screen2.json new file mode 100644 index 0000000..fd9d5ca --- /dev/null +++ b/AlloVictor/Resources/Screen2.json @@ -0,0 +1,311 @@ +{ + "format": "json", + "data": { + "ref_type_id": 101, + "ref_id": 8654097, + "type": "search", + "category_id": 124, + "category_slug": "bricolage-petits-travaux", + "object_id": 5392, + "object_name": "Bricolage - Petits travaux", + "description": "Bonjour, Je cherche une personne qui pourrait me monter cette écran avec caméra intégrée à l'arrière du véhicule je suis livre aujourd'hui , je vie prêt de leclerc paridise à Nantes. Au plaisir de vous lire Merci. Cordialement Sal", + "search_type": 4, + "status": 0, + "start_date": null, + "end_date": null, + "latitude": 47.2182, + "longitude": -1.55947, + "budget": 0, + "duration": 1, + "duration_type": 3, + "is_private_search": false, + "only_pro": false, + "is_category_regulated": false, + "budget_formatted": "À convenir", + "duration_formatted": "", + "location_formatted": "Nantes (Bretagne)", + "distance_formatted": "1000 m", + "published_at_formatted": "le 28 nov. 2023 à 14:56", + "pictures": [ + { + "type": "search_picture", + "id": 9642349, + "picture_urls": { + "large": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_l.jpg", + "small": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_s.jpg" + } + } + ], + "relationships": { + "moment": null, + "leaseholder": { + "id": 5508536, + "type": "user", + "is_pro": false, + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar6.png", + "is_favorite": false, + "is_new_user": true, + "display_name": "Sam F.", + "user_ratings": 0, + "part_pro_status": 0, + "user_ratings_count": 0, + "profile_url": "https://www.allovoisins.com/p/samfalko" + }, + "offerers_users": [ + { + "card_type_id": 351, + "card_type": "card_user", + "ref_type_id": 102, + "ref_id": 5049288, + "first_name": "Noah", + "display_name": "Noah C.", + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar8.png", + "reviews_count": 3, + "average_rating": 4, + "online_latest_activity_at": 12, + "online_latest_activity_at_formatted": "En ligne il y a 12 minutes", + "distance_formatted": "3,6 km", + "location_formatted": "Saint-Sébastien-sur-Loire (Centre)", + "full_location_formatted": "Saint-Sébastien-sur-Loire (Centre)", + "presentation": "Je suis un jeune sportif, dynamiques, je fait de la peinture et je cherche des petit chantiers pour me faire un peu de sous avec plaisir", + "headline": "Noah", + "part_pro_status": 0, + "is_independent": false, + "user_url": "https://www.allovoisins.com/p/noahcatel", + "is_vau": false, + "is_new_user": false, + "is_favorite": false, + "is_available_now": false, + "mobile_phone": null, + "can_report_user": true, + "relationships": { + "gallery_pictures": [ + { + "id": 956086, + "name": "Menuiserie - Huisserie - Agencement", + "type": "gallery_picture", + "image": "https://static.allovoisins.com/uploads/u/galleries/e/f/9/ef91ac28a8_956086_l.jpg", + "ref_id": 956086, + "user_id": 5049288, + "object_id": 5402, + "image_full": "https://static.allovoisins.com/uploads/u/galleries/e/f/9/ef91ac28a8_956086_l.jpg", + "is_service": true, + "category_id": 134, + "description": "Volet à corde ", + "image_large": "https://static.allovoisins.com/uploads/u/galleries/e/f/9/ef91ac28a8_956086_l.jpg", + "image_small": "https://static.allovoisins.com/uploads/u/galleries/e/f/9/ef91ac28a8_956086_s.jpg", + "object_name": "Menuiserie - Huisserie - Agencement", + "ref_type_id": 106, + "category_url": "https://www.allovoisins.com/offreurs/menuiserie-huisserie-agencement/saint-sebastien-sur-loire", + "hidden_by_bo": null, + "picture_urls": { + "large": "https://static.allovoisins.com/uploads/u/galleries/e/f/9/ef91ac28a8_956086_l.jpg", + "small": "https://static.allovoisins.com/uploads/u/galleries/e/f/9/ef91ac28a8_956086_s.jpg" + }, + "category_type": 2, + "relationships": { + "user": { + "type": "user", + "user_id": 5049288, + "user_url": "https://www.allovoisins.com/p/noahcatel", + "city_name": "Saint-Sébastien-sur-Loire", + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar8.png", + "first_name": "Noah", + "display_name": "Noah C.", + "user_ratings": 4, + "district_name": "Centre", + "is_independent": false, + "part_pro_status": 0, + "location_formatted": "Saint-Sébastien-sur-Loire (Centre)", + "user_ratings_count": 3 + } + }, + "date_formatted": "Il y a 1 mois" + }, + { + "id": 935607, + "name": "Peinture - Tapisserie", + "type": "gallery_picture", + "image": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_l.jpg", + "ref_id": 935607, + "user_id": 5049288, + "object_id": 5403, + "image_full": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_l.jpg", + "is_service": true, + "category_id": 135, + "description": "Peinture intérieur ", + "image_large": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_l.jpg", + "image_small": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_s.jpg", + "object_name": "Peinture - Tapisserie", + "ref_type_id": 106, + "category_url": "https://www.allovoisins.com/offreurs/peinture-tapisserie/saint-sebastien-sur-loire", + "hidden_by_bo": null, + "picture_urls": { + "large": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_l.jpg", + "small": "https://static.allovoisins.com/uploads/u/galleries/b/4/f/b4f40a289d_935607_s.jpg" + }, + "category_type": 2, + "relationships": { + "user": { + "type": "user", + "user_id": 5049288, + "user_url": "https://www.allovoisins.com/p/noahcatel", + "city_name": "Saint-Sébastien-sur-Loire", + "avatar_url": "https://static.allovoisins.com/assets/default_avatars/100/Avatar8.png", + "first_name": "Noah", + "display_name": "Noah C.", + "user_ratings": 4, + "district_name": "Centre", + "is_independent": false, + "part_pro_status": 0, + "location_formatted": "Saint-Sébastien-sur-Loire (Centre)", + "user_ratings_count": 3 + } + }, + "date_formatted": "Il y a 2 mois" + } + ] + }, + "meta": { + "messaging_channel_id": 35243121, + "answered_at_formatted": "Réponse envoyée le 28 nov. 2023" + } + }, + { + "card_type_id": 351, + "card_type": "card_user", + "ref_type_id": 102, + "ref_id": 5442223, + "first_name": "Djamel", + "display_name": "Djamel C.", + "avatar_url": "https://static.allovoisins.com/uploads/u/avatars/b/5/7/b57378b7b7_5442223_m.jpg", + "reviews_count": 10, + "average_rating": 4.5, + "online_latest_activity_at": 11, + "online_latest_activity_at_formatted": "En ligne il y a 11 minutes", + "distance_formatted": "5,4 km", + "location_formatted": "Saint-Herblain (Village Expo)", + "full_location_formatted": "Saint-Herblain (Village Expo)", + "presentation": "Ingénieur en informatique.\nInstallateur de panneaux photovoltaïques.\nConception de site web.\nDigital marketing.\nDesign flyer", + "headline": "Ingénieur en informatique,", + "part_pro_status": 0, + "is_independent": false, + "user_url": "https://www.allovoisins.com/p/djamelchebbah", + "is_vau": false, + "is_new_user": false, + "is_favorite": false, + "is_available_now": false, + "mobile_phone": null, + "can_report_user": true, + "relationships": { + "gallery_pictures": [ + { + "id": 942328, + "name": "Installation électrique", + "type": "gallery_picture", + "image": "https://static.allovoisins.com/uploads/u/galleries/2/1/9/2194765440_942328_l.jpg", + "ref_id": 942328, + "user_id": 5442223, + "object_id": 5400, + "image_full": "https://static.allovoisins.com/uploads/u/galleries/2/1/9/2194765440_942328_l.jpg", + "is_service": true, + "category_id": 132, + "description": "Panneaux photovoltaïques ", + "image_large": "https://static.allovoisins.com/uploads/u/galleries/2/1/9/2194765440_942328_l.jpg", + "image_small": "https://static.allovoisins.com/uploads/u/galleries/2/1/9/2194765440_942328_s.jpg", + "object_name": "Installation électrique", + "ref_type_id": 106, + "category_url": "https://www.allovoisins.com/offreurs/installation-electrique/saint-herblain", + "hidden_by_bo": null, + "picture_urls": { + "large": "https://static.allovoisins.com/uploads/u/galleries/2/1/9/2194765440_942328_l.jpg", + "small": "https://static.allovoisins.com/uploads/u/galleries/2/1/9/2194765440_942328_s.jpg" + }, + "category_type": 2, + "relationships": { + "user": { + "type": "user", + "user_id": 5442223, + "user_url": "https://www.allovoisins.com/p/djamelchebbah", + "city_name": "Saint-Herblain", + "avatar_url": "https://static.allovoisins.com/uploads/u/avatars/b/5/7/b57378b7b7_5442223_m.jpg", + "first_name": "Djamel", + "display_name": "Djamel C.", + "user_ratings": 4.5, + "district_name": "Village Expo", + "is_independent": false, + "part_pro_status": 0, + "location_formatted": "Saint-Herblain (Village Expo)", + "user_ratings_count": 10 + } + }, + "date_formatted": "Il y a 1 mois" + }, + { + "id": 942318, + "name": "Installation électrique", + "type": "gallery_picture", + "image": "https://static.allovoisins.com/uploads/u/galleries/e/6/b/e6b5265751_942318_l.jpg", + "ref_id": 942318, + "user_id": 5442223, + "object_id": 5400, + "image_full": "https://static.allovoisins.com/uploads/u/galleries/e/6/b/e6b5265751_942318_l.jpg", + "is_service": true, + "category_id": 132, + "description": "Installation et entretien des kit de panneaux solaires (PV) ", + "image_large": "https://static.allovoisins.com/uploads/u/galleries/e/6/b/e6b5265751_942318_l.jpg", + "image_small": "https://static.allovoisins.com/uploads/u/galleries/e/6/b/e6b5265751_942318_s.jpg", + "object_name": "Installation électrique", + "ref_type_id": 106, + "category_url": "https://www.allovoisins.com/offreurs/installation-electrique/saint-herblain", + "hidden_by_bo": null, + "picture_urls": { + "large": "https://static.allovoisins.com/uploads/u/galleries/e/6/b/e6b5265751_942318_l.jpg", + "small": "https://static.allovoisins.com/uploads/u/galleries/e/6/b/e6b5265751_942318_s.jpg" + }, + "category_type": 2, + "relationships": { + "user": { + "type": "user", + "user_id": 5442223, + "user_url": "https://www.allovoisins.com/p/djamelchebbah", + "city_name": "Saint-Herblain", + "avatar_url": "https://static.allovoisins.com/uploads/u/avatars/b/5/7/b57378b7b7_5442223_m.jpg", + "first_name": "Djamel", + "display_name": "Djamel C.", + "user_ratings": 4.5, + "district_name": "Village Expo", + "is_independent": false, + "part_pro_status": 0, + "location_formatted": "Saint-Herblain (Village Expo)", + "user_ratings_count": 10 + } + }, + "date_formatted": "Il y a 1 mois" + } + ] + }, + "meta": { + "messaging_channel_id": 35243318, + "answered_at_formatted": "Réponse envoyée le 28 nov. 2023" + } + } + ], + "contacted_users": [], + "recommended_users": [], + "social": { + "type": "social", + "answerers_count": 2, + "likes_count": 0, + "shares_count": 0, + "recommendations_count": 0, + "user_has_liked": false, + "user_has_shared": false, + "user_has_reported": false, + "share_link": "https://www.allovoisins.com/s/8654097?utm_source=product_transactionnel&utm_medium=share&utm_campaign=search_details", + "comments_count": null, + "comments": null + } + } + } +} diff --git a/AlloVictor/Screens/NotFoundScreen.swift b/AlloVictor/Screens/NotFoundScreen.swift new file mode 100644 index 0000000..988b46c --- /dev/null +++ b/AlloVictor/Screens/NotFoundScreen.swift @@ -0,0 +1,25 @@ +// +// NotFoundScreen.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI + +struct NotFoundScreen: View { + var body: some View { + ZStack { + VStack { + Spacer() + Image("oups") + .resizable() + .scaledToFit() + Text("L'annonce à laquelle vous essayez d'accéder est introuvable…") + .bold(16) + Spacer() + } + } + .background(Color.white) + } +} diff --git a/AlloVictor/Screens/OfferDetailsScreen.swift b/AlloVictor/Screens/OfferDetailsScreen.swift new file mode 100644 index 0000000..1d0c733 --- /dev/null +++ b/AlloVictor/Screens/OfferDetailsScreen.swift @@ -0,0 +1,50 @@ +// +// OfferDetailsScreen.swift +// AlloVictor +// +// Created by Bodinaud Victor on 14/04/2024. +// + +import SwiftUI + +struct OfferDetailsScreen: View { + @Environment(\.dismiss) var dismiss + + let offerDetails: Offer? + + var body: some View { + VStack { + if offerDetails != nil { + OfferDetailsView(offerDetails: offerDetails!) + } else { + NotFoundScreen() + } + } + .navigationBarBackButtonHidden() + .toolbar(content: { + ToolbarItem(placement: .navigation) { + Button(action: { + dismiss() + }, label: { + Image(systemName: "arrow.backward") + .resizable() + .foregroundStyle(Color.black) + .aspectRatio(contentMode: .fill) + .frame(width: 15, height: 15) + }) + } + + ToolbarItem(placement: .principal) { + Text("Demande publique") + .bold(16) + } + + if offerDetails != nil { + ToolbarItem(placement: .topBarTrailing) { + ShareView(link: offerDetails!.relationships.social?.shareLink ?? "") + } + } + }) + } +} + diff --git a/AlloVictor/Screens/OffersListScreen.swift b/AlloVictor/Screens/OffersListScreen.swift new file mode 100644 index 0000000..434e872 --- /dev/null +++ b/AlloVictor/Screens/OffersListScreen.swift @@ -0,0 +1,56 @@ +// +// OffersListScreen.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import SwiftUI + +struct OffersListScreen: View { + @EnvironmentObject private var viewModel: AlloVictorViewModel + + var body: some View { + ScrollView { + LazyVStack { + ForEach(viewModel.offersList) { offer in + if offer.cardType == .publicSearch { + OfferListView(offer: offer, offerDetails: viewModel.offerDetails[offer.id]) + } else if offer.cardType == .alloFlash { + AlloFlashView(offer: offer) + } + } + } + } + .background(Color.neutral20) + .toolbar(content: { + ToolbarItem(placement: .topBarLeading) { + Button(action: {}, label: { + AvatarView(avatarUrl: "", width: 35, height: 35) + }) + } + + ToolbarItem(placement: .principal) { + VStack { + Image("SimpleLogo") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(height: 25) + Text("Nantes (Procès)") + .medium(12) + .foregroundStyle(Color.gray) + } + } + + ToolbarItem(placement: .topBarTrailing) { + Button(action: {}, label: { + Image(systemName: "bell") + }) + .foregroundColor(.black) + } + }) + .navigationBarTitleDisplayMode(.inline) + .toolbarBackground(.white, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + } +} diff --git a/AlloVictor/Screens/ShowFullPictureScreen.swift b/AlloVictor/Screens/ShowFullPictureScreen.swift new file mode 100644 index 0000000..98bbc54 --- /dev/null +++ b/AlloVictor/Screens/ShowFullPictureScreen.swift @@ -0,0 +1,26 @@ +// +// ShowFullPictureScreen.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI +import CachedAsyncImage + +struct ShowFullPictureScreen: View { + let pictureUrl: String + + var body: some View { + VStack(alignment: .trailing) { + CachedAsyncImage(url: URL(string: pictureUrl)) { image in + image + .resizable() + .scaledToFit() + + } placeholder: { + ProgressView() + } + } + } +} diff --git a/AlloVictor/Utils/Constants.swift b/AlloVictor/Utils/Constants.swift new file mode 100644 index 0000000..0c667a8 --- /dev/null +++ b/AlloVictor/Utils/Constants.swift @@ -0,0 +1,17 @@ +// +// Constants.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import Foundation + +struct Constants { + public static let baseUrl = "https://git.mahtan-melwasul.com/Mahtan/AlloVictor/raw/branch/develop/AlloVictor/Resources" + + struct Urls { + static let list = URL(string: "\(baseUrl)/Screen1.json")! + static let detail = URL(string: "\(baseUrl)/Screen2.json")! + } +} diff --git a/AlloVictor/Utils/HTTPClient.swift b/AlloVictor/Utils/HTTPClient.swift new file mode 100644 index 0000000..bf4d09b --- /dev/null +++ b/AlloVictor/Utils/HTTPClient.swift @@ -0,0 +1,74 @@ +// +// HTTPClient.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import Foundation + +enum NetworkError: Error { + case badRequest + case invalideResponse + case failedDecoding +} + +enum HTTPMethod { + case get + + var name: String { + switch self { + case .get: + return "GET" + } + } +} + +struct Resource { + let url: URL + var method: HTTPMethod = .get + var modelType: T.Type +} + +struct HTTPClient { + + private var defaultHeaders: [String: String] { + let headers = ["Content-Type": "application/json"] + + return headers + } + + public func load(_ resource: Resource) async throws -> T { + var request = URLRequest(url: resource.url) + + switch resource.method { + case .get: + let components = URLComponents(url: resource.url, resolvingAgainstBaseURL: false) + guard let url = components?.url else { + throw NetworkError.badRequest + } + + request = URLRequest(url: url) + } + + let configuration = URLSessionConfiguration.default + configuration.httpAdditionalHeaders = defaultHeaders + let session = URLSession(configuration: configuration) + + let (data, response) = try await session.data(for: request) + + guard let _ = response as? HTTPURLResponse else { + throw NetworkError.invalideResponse + } + + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + + guard let result = try? + decoder.decode(resource.modelType, from: data) else { + throw NetworkError.failedDecoding + } + + return result + } +} diff --git a/AlloVictor/ViewModels/AlloVictorViewModel.swift b/AlloVictor/ViewModels/AlloVictorViewModel.swift new file mode 100644 index 0000000..05b7147 --- /dev/null +++ b/AlloVictor/ViewModels/AlloVictorViewModel.swift @@ -0,0 +1,26 @@ +// +// AlloVictorViewModel.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import Foundation + +@MainActor +class AlloVictorViewModel: ObservableObject { + @Published var offersList: [Offer] = [] + @Published var offerDetails: [Int: Offer] = [:] + + let httpClient = HTTPClient() + + func getDatas() async throws { + let listResource = Resource(url: Constants.Urls.list, modelType: OfferListResponseDTO.self) + let detailsResource = Resource(url: Constants.Urls.detail, modelType: OfferDetailsResponseDTO.self) + + offersList = try await httpClient.load(listResource).data + let offer = try await httpClient.load(detailsResource).data + + offerDetails[offer.id] = offer + } +} diff --git a/AlloVictor/Views/AlloFlashView.swift b/AlloVictor/Views/AlloFlashView.swift new file mode 100644 index 0000000..37d3f27 --- /dev/null +++ b/AlloVictor/Views/AlloFlashView.swift @@ -0,0 +1,58 @@ +// +// AlloFlashView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import SwiftUI +import CachedAsyncImage + +struct AlloFlashView: View { + @State private var isLiked = false + let offer: Offer + + var body: some View { + VStack { + VStack(alignment: .leading) { + HStack { + Image("Icon") + .resizable() + .frame(width: 25, height: 25) + .aspectRatio(contentMode: .fit) + Text("AlloFlash") + .medium(13) + } + Divider() + } + .padding([.leading, .trailing]) + CachedAsyncImage(url: URL(string: offer.sectionBackgroundImage ?? "")) { image in + image + .resizable() + .aspectRatio(contentMode: .fit) + } placeholder: { + ProgressView() + } + VStack(alignment: .leading) { + HStack { + Text("\(offer.relationships.social?.likesCount ?? 0) j'aime") + .regular(12) + } + Divider() + Button(action: { + isLiked.toggle() + }, label: { + HStack { + Image(systemName: isLiked ? "heart.fill" : "heart") + .foregroundStyle(isLiked ? Color.red : Color.black) + Text("J'aime") + .medium(14) + } + }) + } + .padding([.leading, .trailing, .bottom]) + } + .buttonStyle(PlainButtonStyle()) + .background(Color.white) + } +} diff --git a/AlloVictor/Views/Components/AvatarView.swift b/AlloVictor/Views/Components/AvatarView.swift new file mode 100644 index 0000000..2a377bf --- /dev/null +++ b/AlloVictor/Views/Components/AvatarView.swift @@ -0,0 +1,31 @@ +// +// AvatarView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 15/04/2024. +// + +import SwiftUI +import CachedAsyncImage + +struct AvatarView: View { + let avatarUrl: String + let width: CGFloat + let height: CGFloat + + var body: some View { + CachedAsyncImage(url: URL(string: avatarUrl)) { image in + image + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: width, height: height) + .clipShape(Circle()) + } placeholder: { + Image("Avatar") + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: width, height: height) + .clipShape(Circle()) + } + } +} diff --git a/AlloVictor/Views/Components/Offer/OfferBodyView.swift b/AlloVictor/Views/Components/Offer/OfferBodyView.swift new file mode 100644 index 0000000..a308bd3 --- /dev/null +++ b/AlloVictor/Views/Components/Offer/OfferBodyView.swift @@ -0,0 +1,45 @@ +// +// OfferBodyView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI +import CachedAsyncImage + +struct OfferBodyView: View { + let offer: Offer + + var body: some View { + HStack(alignment: .top) { + AvatarView(avatarUrl: offer.relationships.leaseholder?.avatarUrl ?? "", width: 50, height: 50) + + VStack(alignment: .leading, spacing: 8) { + Text(offer.relationships.leaseholder?.displayName ?? "") + .demiBold(16) + Text(offer.desc ?? "") + .regular(16) + + if offer.searchPictureUrl != nil { + CachedAsyncImage(url: URL(string: offer.searchPictureUrl!)) { image in + image + .resizable() + .cornerRadius(8) + .scaledToFit() + } placeholder: { + ProgressView() + .padding() + } + } + + VStack(alignment: .leading, spacing: 4) { + Text("\(offer.locationFormatted ?? "") - \(offer.distanceFormatted ?? "")") + .regular(12) + Text("Budget: \(offer.budgetFormatted ?? "")") + .regular(12) + } + } + } + } +} diff --git a/AlloVictor/Views/Components/Offer/OfferHeaderView.swift b/AlloVictor/Views/Components/Offer/OfferHeaderView.swift new file mode 100644 index 0000000..9098b9a --- /dev/null +++ b/AlloVictor/Views/Components/Offer/OfferHeaderView.swift @@ -0,0 +1,24 @@ +// +// OfferHeaderView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI + +struct OfferHeaderView: View { + let publishedAt: String + + var body: some View { + HStack { + Image(systemName: "globe.americas.fill") + .foregroundStyle(Color.black) + Text("Demande publique") + .medium(13) + Spacer() + Text(publishedAt) + .regular(12) + } + } +} diff --git a/AlloVictor/Views/Components/Offer/OfferSocialView.swift b/AlloVictor/Views/Components/Offer/OfferSocialView.swift new file mode 100644 index 0000000..f22763b --- /dev/null +++ b/AlloVictor/Views/Components/Offer/OfferSocialView.swift @@ -0,0 +1,54 @@ +// +// OfferSocialView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 14/04/2024. +// + +import SwiftUI + +struct OfferSocialView: View { + @State private var isLiked = false + let social: Social + + var body: some View { + VStack(spacing: 8) { + HStack { + Text("\(social.likesCount) j'aime") + .regular(12) + Spacer() + Text("\(social.answerersCount ?? 0) réponses") + .regular(12) + } + Divider() + HStack { + Button(action: { + isLiked.toggle() + }, label: { + Image(systemName: isLiked ? "heart.fill" : "heart") + .foregroundStyle(isLiked ? Color.red : Color.black) + Text("J'aime") + .medium(14) + }) + Spacer() + + Button(action: {}, label: { + Image(systemName: "person.3") + .foregroundStyle(Color.black) + Text("Recommander") + .medium(14) + }) + Spacer() + + Button(action: {}, label: { + Image(systemName: "ellipsis.message") + .foregroundStyle(Color.black) + Text("Répondre") + .medium(14) + }) + } + .buttonStyle(PlainButtonStyle()) + } + .padding() + } +} diff --git a/AlloVictor/Views/Components/OfferDetails/OfferDetailsAwnserCountView.swift b/AlloVictor/Views/Components/OfferDetails/OfferDetailsAwnserCountView.swift new file mode 100644 index 0000000..e00dc0f --- /dev/null +++ b/AlloVictor/Views/Components/OfferDetails/OfferDetailsAwnserCountView.swift @@ -0,0 +1,21 @@ +// +// OfferDetailsAwnserCountView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI + +struct OfferDetailsAwnserCountView: View { + let awnserCount: Int + + var body: some View { + HStack { + Image(systemName: "ellipsis.message") + Text("\(awnserCount) offreurs ont répondu") + } + .bold(18) + .padding([.leading, .trailing]) + } +} diff --git a/AlloVictor/Views/Components/OfferDetails/OfferDetailsBodyView.swift b/AlloVictor/Views/Components/OfferDetails/OfferDetailsBodyView.swift new file mode 100644 index 0000000..7890be9 --- /dev/null +++ b/AlloVictor/Views/Components/OfferDetails/OfferDetailsBodyView.swift @@ -0,0 +1,61 @@ +// +// OfferDetailsBodyView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI +import MapKit + +struct OfferDetailsBodyView: View { + let offerDetails: Offer + + var body: some View { + VStack { + HStack(alignment: .top) { + AvatarView(avatarUrl: offerDetails.relationships.leaseholder?.avatarUrl ?? "", width: 50, height: 50) + + VStack(alignment: .leading, spacing: 8) { + HStack { + if offerDetails.relationships.leaseholder != nil { + OfferDetailsLeaseholderInfosView(leaseholder: offerDetails.relationships.leaseholder!) + } + + Spacer() + + VStack(alignment: .trailing) { + Text("demande postée") + .medium(12) + Text(offerDetails.publishedAtFormatted ?? "") + .medium(12) + } + } + + Text(offerDetails.desc ?? "") + .regular(16) + + if offerDetails.pictures != nil { + OfferDetailsGalleryView(pictures: offerDetails.pictures!) + } + + OfferDetailsMapView(latitude: offerDetails.latitude!, longitude: offerDetails.longitude!) + .frame(height: 150) + .cornerRadius(8) + + VStack(alignment: .leading, spacing: 4) { + Text("\(offerDetails.locationFormatted!) - \(offerDetails.distanceFormatted!)") + .regular(12) + Text("Budget: \(offerDetails.budgetFormatted!)") + .regular(12) + Text("Catégorie : \(offerDetails.objectName!)") + .regular(12) + } + } + } + .padding([.leading, .trailing]) + + OfferSocialView(social: offerDetails.relationships.social!) + } + } +} diff --git a/AlloVictor/Views/Components/OfferDetails/OfferDetailsGalleryView.swift b/AlloVictor/Views/Components/OfferDetails/OfferDetailsGalleryView.swift new file mode 100644 index 0000000..248be21 --- /dev/null +++ b/AlloVictor/Views/Components/OfferDetails/OfferDetailsGalleryView.swift @@ -0,0 +1,35 @@ +// +// OfferDetailsGalleryView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI +import CachedAsyncImage + +struct OfferDetailsGalleryView: View { + @State var showFullScreenPicture = false + let pictures: [OfferPicture] + + var body: some View { + ForEach(pictures) { picture in + CachedAsyncImage(url: URL(string: picture.pictureUrls.large)) { image in + image + .resizable() + .cornerRadius(8) + .scaledToFit() + } placeholder: { + ProgressView() + .padding() + } + .sheet(isPresented: $showFullScreenPicture, content: { + ShowFullPictureScreen(pictureUrl: picture.pictureUrls.large) + }) + .onTapGesture { + showFullScreenPicture.toggle() + } + + } + } +} diff --git a/AlloVictor/Views/Components/OfferDetails/OfferDetailsLeaseholderInfosView.swift b/AlloVictor/Views/Components/OfferDetails/OfferDetailsLeaseholderInfosView.swift new file mode 100644 index 0000000..b21a79b --- /dev/null +++ b/AlloVictor/Views/Components/OfferDetails/OfferDetailsLeaseholderInfosView.swift @@ -0,0 +1,26 @@ +// +// OfferDetailsLeaseholderInfosView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI + +struct OfferDetailsLeaseholderInfosView: View { + var leaseholder: Leaseholder + + var body: some View { + VStack(alignment: .leading) { + Text(leaseholder.displayName) + .demiBold(16) + HStack { + Image(systemName: "star.fill") + .foregroundStyle(Color.neutral20) + Text("\(leaseholder.userRatings == 0 ? "-" : "\(leaseholder.userRatings)")/5") + .bold(14) + } + .regular(12) + } + } +} diff --git a/AlloVictor/Views/Components/OfferDetails/OfferDetailsMapView.swift b/AlloVictor/Views/Components/OfferDetails/OfferDetailsMapView.swift new file mode 100644 index 0000000..1845070 --- /dev/null +++ b/AlloVictor/Views/Components/OfferDetails/OfferDetailsMapView.swift @@ -0,0 +1,32 @@ +// +// OfferDetailsMapView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI +import MapKit + +struct OfferDetailsMapView: View { + let latitude: Double + let longitude: Double + + var body: some View { + Map(bounds: MapCameraBounds(minimumDistance: 8000), interactionModes: []) { + Annotation("", coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude)) { + AvatarView(avatarUrl: "", width: 40, height: 40) + } + } + .mapStyle( + .standard( + pointsOfInterest: .excludingAll, + showsTraffic: false + ) + ) + } +} + +#Preview { + OfferDetailsMapView(latitude: 47.2182, longitude: -1.55947) +} diff --git a/AlloVictor/Views/Components/OffererUser/OffererUserGallery.swift b/AlloVictor/Views/Components/OffererUser/OffererUserGallery.swift new file mode 100644 index 0000000..c7aa49b --- /dev/null +++ b/AlloVictor/Views/Components/OffererUser/OffererUserGallery.swift @@ -0,0 +1,31 @@ +// +// OffererUserGallery.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI +import CachedAsyncImage + +struct OffererUserGallery: View { + let gallery: [GalleryPicture] + + var body: some View { + ScrollView(.horizontal) { + HStack { + ForEach(gallery) { picture in + CachedAsyncImage(url: URL(string: picture.imageSmall)) { image in + image + .resizable() + .frame(width: 200, height: 100) + .scaledToFill() + } placeholder: { + ProgressView() + } + } + } + } + .scrollIndicators(.hidden) + } +} diff --git a/AlloVictor/Views/Components/OffererUser/OffererUserInfos.swift b/AlloVictor/Views/Components/OffererUser/OffererUserInfos.swift new file mode 100644 index 0000000..4185bbf --- /dev/null +++ b/AlloVictor/Views/Components/OffererUser/OffererUserInfos.swift @@ -0,0 +1,30 @@ +// +// OffererUserInfos.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI + +struct OffererUserInfos: View { + let offererUser: OfferersUser + + var body: some View { + VStack(alignment: .leading) { + HStack { + AvatarView(avatarUrl: offererUser.avatarUrl, width: 65, height: 65) + VStack(alignment: .leading) { + Text(offererUser.displayName) + .medium(15) + Text(offererUser.headline) + .medium(12) + Text("\(offererUser.locationFormatted) - à \(offererUser.distanceFormatted)") + .light(12) + Text(offererUser.onlineLatestActivityAtFormatted) + .light(12) + } + } + } + } +} diff --git a/AlloVictor/Views/Components/OffererUser/OffererUserProStatusView.swift b/AlloVictor/Views/Components/OffererUser/OffererUserProStatusView.swift new file mode 100644 index 0000000..c6fa00c --- /dev/null +++ b/AlloVictor/Views/Components/OffererUser/OffererUserProStatusView.swift @@ -0,0 +1,20 @@ +// +// OffererUserProStatusView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI + +struct OffererUserProStatusView: View { + let isIndependent: Bool + + var body: some View { + Text(isIndependent ? "Auto-entrepreneur" : "Particulier") + .demiBold(12) + .padding(4) + .background(isIndependent ? Color.grape30 : Color.neutral20) + .cornerRadius(5) + } +} diff --git a/AlloVictor/Views/Components/OffererUser/OffererUserRatingView.swift b/AlloVictor/Views/Components/OffererUser/OffererUserRatingView.swift new file mode 100644 index 0000000..601b2a3 --- /dev/null +++ b/AlloVictor/Views/Components/OffererUser/OffererUserRatingView.swift @@ -0,0 +1,24 @@ +// +// OffererUserRatingView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 18/04/2024. +// + +import SwiftUI + +struct OffererUserRatingView: View { + let averageRating: Double + let reviewsCount: Int + + var body: some View { + HStack { + Image(systemName: "star.fill") + .foregroundStyle(Color.yellow) + Text("\(String(format: "%.1f", averageRating))/5") + .demiBold(18) + Text("(\(reviewsCount) avis)") + .bold(14) + } + } +} diff --git a/AlloVictor/Views/Components/ShareView.swift b/AlloVictor/Views/Components/ShareView.swift new file mode 100644 index 0000000..20e0cb0 --- /dev/null +++ b/AlloVictor/Views/Components/ShareView.swift @@ -0,0 +1,25 @@ +// +// ShareView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 14/04/2024. +// + +import SwiftUI + +struct ShareView: View { + let link: String + + var body: some View { + HStack { + ShareLink(item: URL(string: link)!) { + Image(systemName: "square.and.arrow.up") + } + .foregroundColor(.black) + Button(action: {}, label: { + Image(systemName: "ellipsis.circle") + }) + .foregroundColor(.black) + } + } +} diff --git a/AlloVictor/Views/Modifiers/TextModifier.swift b/AlloVictor/Views/Modifiers/TextModifier.swift new file mode 100644 index 0000000..2ac6f89 --- /dev/null +++ b/AlloVictor/Views/Modifiers/TextModifier.swift @@ -0,0 +1,89 @@ +// +// TextModifier.swift +// AlloVictor +// +// Created by Bodinaud Victor on 14/04/2024. +// + +import Foundation +import SwiftUI + +struct AlloTextExtraLight: ViewModifier { + let size: CGFloat + + func body(content: Content) -> some View { + content + .font(.custom("TTChocolates-ExtraLight", size: size)) + } +} + +struct AlloTextLight: ViewModifier { + let size: CGFloat + + func body(content: Content) -> some View { + content + .font(.custom("TTChocolates-Light", size: size)) + } +} + +struct AlloTextRegular: ViewModifier { + let size: CGFloat + + func body(content: Content) -> some View { + content + .font(.custom("TTChocolates-Regular", size: size)) + } +} + +struct AlloTextMedium: ViewModifier { + let size: CGFloat + + func body(content: Content) -> some View { + content + .font(.custom("TTChocolates-Medium", size: size)) + } +} + +struct AlloTextDemiBold: ViewModifier { + let size: CGFloat + + func body(content: Content) -> some View { + content + .font(.custom("TTChocolates-DemiBold", size: size)) + } +} + +struct AlloTextBold: ViewModifier { + let size: CGFloat + + func body(content: Content) -> some View { + content + .font(.custom("TTChocolates-Bold", size: size)) + } +} + +extension View { + func extraLight(_ size: CGFloat) -> some View { + modifier(AlloTextExtraLight(size: size)) + } + + func light(_ size: CGFloat) -> some View { + modifier(AlloTextLight(size: size)) + } + + func regular(_ size: CGFloat) -> some View { + modifier(AlloTextRegular(size: size)) + } + + func medium(_ size: CGFloat) -> some View { + modifier(AlloTextMedium(size: size)) + } + + func demiBold(_ size: CGFloat) -> some View { + modifier(AlloTextDemiBold(size: size)) + } + + func bold(_ size: CGFloat) -> some View { + modifier(AlloTextBold(size: size)) + } +} diff --git a/AlloVictor/Views/OfferDetailsView.swift b/AlloVictor/Views/OfferDetailsView.swift new file mode 100644 index 0000000..c4f427b --- /dev/null +++ b/AlloVictor/Views/OfferDetailsView.swift @@ -0,0 +1,50 @@ +// +// OfferDetailsView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 14/04/2024. +// + +import SwiftUI +import MapKit + +struct OfferDetailsView: View { + let offerDetails: Offer + + var body: some View { + ScrollView { + LazyVStack(alignment: .leading) { + OfferDetailsBodyView(offerDetails: offerDetails) + + OfferDetailsAwnserCountView(awnserCount: offerDetails.relationships.social?.answerersCount ?? 0) + + ForEach(offerDetails.relationships.offerersUsers!) { offererUser in + OffererUserView(offererUser: offererUser) + .padding() + } + } + } + .background(Color.white) + .toolbar { + ToolbarItemGroup(placement: .bottomBar) { + HStack(alignment: .center) { + Button(action: {}, label: { + HStack { + Image(systemName: "ellipsis.message") + .foregroundStyle(Color.white) + Text("Répondre") + .bold(14) + .foregroundStyle(Color.white) + } + }) + .padding([.top, .bottom], 4) + .padding([.leading, .trailing], 16) + .background(Color.pillButton) + .clipShape(Capsule()) + .foregroundStyle(Color.white) + } + } + } + .toolbarColorScheme(.light) + } +} diff --git a/AlloVictor/Views/OfferListView.swift b/AlloVictor/Views/OfferListView.swift new file mode 100644 index 0000000..a65b83c --- /dev/null +++ b/AlloVictor/Views/OfferListView.swift @@ -0,0 +1,33 @@ +// +// OfferListView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 13/04/2024. +// + +import SwiftUI +import CachedAsyncImage + +struct OfferListView: View { + let offer: Offer + let offerDetails: Offer? + + var body: some View { + VStack { + NavigationLink(value: Route.detail(offerDetails)) { + VStack { + OfferHeaderView(publishedAt: offer.publishedAtFormatted ?? "") + + Divider() + + OfferBodyView(offer: offer) + } + } + .padding() + .buttonStyle(PlainButtonStyle()) + + OfferSocialView(social: offer.relationships.social!) + } + .background(Color.white) + } +} diff --git a/AlloVictor/Views/OffererUserView.swift b/AlloVictor/Views/OffererUserView.swift new file mode 100644 index 0000000..71f969f --- /dev/null +++ b/AlloVictor/Views/OffererUserView.swift @@ -0,0 +1,36 @@ +// +// OffererUserView.swift +// AlloVictor +// +// Created by Bodinaud Victor on 14/04/2024. +// + +import SwiftUI + +struct OffererUserView: View { + let offererUser: OfferersUser + + var body: some View { + VStack(alignment: .trailing) { + VStack(alignment: .trailing) { + OffererUserProStatusView(isIndependent: offererUser.isIndependent) + + VStack(alignment: .leading) { + OffererUserInfos(offererUser: offererUser) + .padding([.leading, .trailing]) + + if offererUser.relationships.galleryPictures != nil { + OffererUserGallery(gallery: offererUser.relationships.galleryPictures!) + } + + OffererUserRatingView(averageRating: offererUser.averageRating, reviewsCount: offererUser.reviewsCount) + .padding() + } + } + .background(Color.white) + .addBorder(Color.neutral20, cornerRadius: 5) + Text(offererUser.meta.answeredAtFormatted) + .regular(12) + } + } +}