diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000..c4274ddb25 Binary files /dev/null and b/.DS_Store differ diff --git a/FakeNFT.xcodeproj/project.pbxproj b/FakeNFT.xcodeproj/project.pbxproj index 4ab702c8c3..56e6962fec 100644 --- a/FakeNFT.xcodeproj/project.pbxproj +++ b/FakeNFT.xcodeproj/project.pbxproj @@ -27,7 +27,41 @@ 3FC8C38B29D242E90081F015 /* ProductDetailsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC8C38A29D242E90081F015 /* ProductDetailsTableViewCell.swift */; }; 3FC8C39129D2453B0081F015 /* ExampleRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC8C39029D2453B0081F015 /* ExampleRequest.swift */; }; 3FC8C39329D246BA0081F015 /* DateFormatters+Presets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC8C39229D246BA0081F015 /* DateFormatters+Presets.swift */; }; - 3FC8C39729D24D9D0081F015 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 3FC8C39629D24D9D0081F015 /* .swiftlint.yml */; }; + 65898AFF2AF36012000930F6 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65898AFE2AF36012000930F6 /* User.swift */; }; + 65898B012AF3604A000930F6 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65898B002AF3604A000930F6 /* Config.swift */; }; + 65898B032AF36085000930F6 /* Models&Structs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65898B022AF36085000930F6 /* Models&Structs.swift */; }; + 65898B052AF36138000930F6 /* StatisticsUserProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65898B042AF36138000930F6 /* StatisticsUserProfileViewModel.swift */; }; + 65898B0B2AF365D9000930F6 /* RatingStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65898B0A2AF365D9000930F6 /* RatingStackView.swift */; }; + 65898B132AF36721000930F6 /* UIBlockingProgressHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65898B122AF36721000930F6 /* UIBlockingProgressHUD.swift */; }; + A226A86B2ACFECE500E782E3 /* CatalogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A226A86A2ACFECE500E782E3 /* CatalogViewController.swift */; }; + A226A86F2ACFF2A900E782E3 /* ShoppingCartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A226A86E2ACFF2A900E782E3 /* ShoppingCartViewController.swift */; }; + A226A8712ACFF2BA00E782E3 /* StatisticsUserProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A226A8702ACFF2BA00E782E3 /* StatisticsUserProfileViewController.swift */; }; + A226A8732ACFF4B500E782E3 /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A226A8722ACFF4B500E782E3 /* TabBarController.swift */; }; + A226A8752ACFF69B00E782E3 /* ProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A226A8742ACFF69B00E782E3 /* ProfileViewModel.swift */; }; + A226A8772ACFF72500E782E3 /* CatalogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A226A8762ACFF72500E782E3 /* CatalogViewModel.swift */; }; + A226A8792ACFF76900E782E3 /* ShoppingCartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A226A8782ACFF76900E782E3 /* ShoppingCartViewModel.swift */; }; + A226A87B2ACFF78900E782E3 /* StatisticsUserProfileModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A226A87A2ACFF78900E782E3 /* StatisticsUserProfileModel.swift */; }; + A2D5203D2ACF2B210083FAA7 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2D5203C2ACF2B210083FAA7 /* ProfileViewController.swift */; }; + A3F9D5FF2AF38B0500F66038 /* StatisticsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D5FE2AF38B0500F66038 /* StatisticsRouter.swift */; }; + A3F9D6012AF3900A00F66038 /* StatisticsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6002AF3900A00F66038 /* StatisticsViewController.swift */; }; + A3F9D6032AF3903000F66038 /* StatisticsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6022AF3903000F66038 /* StatisticsTableViewCell.swift */; }; + A3F9D6052AF3905300F66038 /* ProfileCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6042AF3905300F66038 /* ProfileCellView.swift */; }; + A3F9D6072AF3906900F66038 /* StatisticsTableViewCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6062AF3906900F66038 /* StatisticsTableViewCellModel.swift */; }; + A3F9D60C2AF390DE00F66038 /* ServerUserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D60B2AF390DE00F66038 /* ServerUserModel.swift */; }; + A3F9D60E2AF3910100F66038 /* StatisticsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D60D2AF3910100F66038 /* StatisticsLoader.swift */; }; + A3F9D6102AF3916500F66038 /* StatisticsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D60F2AF3916500F66038 /* StatisticsViewModel.swift */; }; + A3F9D6122AF3917E00F66038 /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6112AF3917E00F66038 /* UserModel.swift */; }; + A3F9D6152AF3921100F66038 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6142AF3921100F66038 /* Observable.swift */; }; + A3F9D6172AF3932E00F66038 /* EndPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6162AF3932E00F66038 /* EndPoint.swift */; }; + A3F9D6192AF3962500F66038 /* UIView+Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6182AF3962500F66038 /* UIView+Layout.swift */; }; + A3F9D61B2AF397BC00F66038 /* GeometricParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D61A2AF397BC00F66038 /* GeometricParams.swift */; }; + A3F9D61E2AF3981500F66038 /* WebKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D61D2AF3981500F66038 /* WebKit.swift */; }; + A3F9D6232AF39E6B00F66038 /* StatisticsNFTModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6222AF39E6A00F66038 /* StatisticsNFTModel.swift */; }; + A3F9D6252AF39E8100F66038 /* StatisticsUserNFTCollectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6242AF39E8100F66038 /* StatisticsUserNFTCollectionModel.swift */; }; + A3F9D6272AF39EA000F66038 /* StatisticsUserNFTCollectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6262AF39EA000F66038 /* StatisticsUserNFTCollectionViewModel.swift */; }; + A3F9D6292AF39EB700F66038 /* StatisticsUserNFTCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D6282AF39EB700F66038 /* StatisticsUserNFTCollectionViewController.swift */; }; + A3F9D62B2AF39ECE00F66038 /* StatisticsUserNFTCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D62A2AF39ECE00F66038 /* StatisticsUserNFTCollectionViewCell.swift */; }; + A3F9D62D2AF39EE400F66038 /* StatisticsUserNFTCollectionCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3F9D62C2AF39EE400F66038 /* StatisticsUserNFTCollectionCellModel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -70,7 +104,41 @@ 3FC8C38A29D242E90081F015 /* ProductDetailsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductDetailsTableViewCell.swift; sourceTree = ""; }; 3FC8C39029D2453B0081F015 /* ExampleRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleRequest.swift; sourceTree = ""; }; 3FC8C39229D246BA0081F015 /* DateFormatters+Presets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatters+Presets.swift"; sourceTree = ""; }; - 3FC8C39629D24D9D0081F015 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; + 65898AFE2AF36012000930F6 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + 65898B002AF3604A000930F6 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; + 65898B022AF36085000930F6 /* Models&Structs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Models&Structs.swift"; sourceTree = ""; }; + 65898B042AF36138000930F6 /* StatisticsUserProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsUserProfileViewModel.swift; sourceTree = ""; }; + 65898B0A2AF365D9000930F6 /* RatingStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingStackView.swift; sourceTree = ""; }; + 65898B122AF36721000930F6 /* UIBlockingProgressHUD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIBlockingProgressHUD.swift; sourceTree = ""; }; + A226A86A2ACFECE500E782E3 /* CatalogViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CatalogViewController.swift; sourceTree = ""; }; + A226A86E2ACFF2A900E782E3 /* ShoppingCartViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShoppingCartViewController.swift; sourceTree = ""; }; + A226A8702ACFF2BA00E782E3 /* StatisticsUserProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsUserProfileViewController.swift; sourceTree = ""; }; + A226A8722ACFF4B500E782E3 /* TabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; }; + A226A8742ACFF69B00E782E3 /* ProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewModel.swift; sourceTree = ""; }; + A226A8762ACFF72500E782E3 /* CatalogViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogViewModel.swift; sourceTree = ""; }; + A226A8782ACFF76900E782E3 /* ShoppingCartViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShoppingCartViewModel.swift; sourceTree = ""; }; + A226A87A2ACFF78900E782E3 /* StatisticsUserProfileModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsUserProfileModel.swift; sourceTree = ""; }; + A2D5203C2ACF2B210083FAA7 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; + A3F9D5FE2AF38B0500F66038 /* StatisticsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsRouter.swift; sourceTree = ""; }; + A3F9D6002AF3900A00F66038 /* StatisticsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsViewController.swift; sourceTree = ""; }; + A3F9D6022AF3903000F66038 /* StatisticsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsTableViewCell.swift; sourceTree = ""; }; + A3F9D6042AF3905300F66038 /* ProfileCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileCellView.swift; sourceTree = ""; }; + A3F9D6062AF3906900F66038 /* StatisticsTableViewCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsTableViewCellModel.swift; sourceTree = ""; }; + A3F9D60B2AF390DE00F66038 /* ServerUserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerUserModel.swift; sourceTree = ""; }; + A3F9D60D2AF3910100F66038 /* StatisticsLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsLoader.swift; sourceTree = ""; }; + A3F9D60F2AF3916500F66038 /* StatisticsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsViewModel.swift; sourceTree = ""; }; + A3F9D6112AF3917E00F66038 /* UserModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = ""; }; + A3F9D6142AF3921100F66038 /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; + A3F9D6162AF3932E00F66038 /* EndPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndPoint.swift; sourceTree = ""; }; + A3F9D6182AF3962500F66038 /* UIView+Layout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Layout.swift"; sourceTree = ""; }; + A3F9D61A2AF397BC00F66038 /* GeometricParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeometricParams.swift; sourceTree = ""; }; + A3F9D61D2AF3981500F66038 /* WebKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebKit.swift; sourceTree = ""; }; + A3F9D6222AF39E6A00F66038 /* StatisticsNFTModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsNFTModel.swift; sourceTree = ""; }; + A3F9D6242AF39E8100F66038 /* StatisticsUserNFTCollectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsUserNFTCollectionModel.swift; sourceTree = ""; }; + A3F9D6262AF39EA000F66038 /* StatisticsUserNFTCollectionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsUserNFTCollectionViewModel.swift; sourceTree = ""; }; + A3F9D6282AF39EB700F66038 /* StatisticsUserNFTCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsUserNFTCollectionViewController.swift; sourceTree = ""; }; + A3F9D62A2AF39ECE00F66038 /* StatisticsUserNFTCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsUserNFTCollectionViewCell.swift; sourceTree = ""; }; + A3F9D62C2AF39EE400F66038 /* StatisticsUserNFTCollectionCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsUserNFTCollectionCellModel.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -112,7 +180,6 @@ 3F68068A29CBBAF100B4F915 = { isa = PBXGroup; children = ( - 3FC8C39629D24D9D0081F015 /* .swiftlint.yml */, 3F68069529CBBAF100B4F915 /* FakeNFT */, 3F6806AC29CBBAF200B4F915 /* FakeNFTTests */, 3F6806B629CBBAF200B4F915 /* FakeNFTUITests */, @@ -135,6 +202,7 @@ children = ( 3F68069629CBBAF100B4F915 /* AppDelegate.swift */, 3F68069829CBBAF100B4F915 /* SceneDelegate.swift */, + A226A8722ACFF4B500E782E3 /* TabBarController.swift */, 3F478ECD29DB473000F6D39E /* DesignSystem */, 3F6806CE29CBBD1B00B4F915 /* Foundation */, 3F6806C929CBBCAF00B4F915 /* Models */, @@ -175,6 +243,10 @@ 3F6806C729CBBC5B00B4F915 /* Scenes */ = { isa = PBXGroup; children = ( + A226A86D2ACFF27B00E782E3 /* Statistics */, + A226A86C2ACFF1F000E782E3 /* ShoppingCart */, + A226A8692ACFECE500E782E3 /* Catalog */, + A2D5203B2ACF2B070083FAA7 /* Profile */, 3F6806C829CBBC8100B4F915 /* ProductDetails */, ); path = "Scenes "; @@ -193,6 +265,9 @@ isa = PBXGroup; children = ( 3F6806D829CC979D00B4F915 /* Network */, + 65898AFE2AF36012000930F6 /* User.swift */, + 65898B002AF3604A000930F6 /* Config.swift */, + 65898B022AF36085000930F6 /* Models&Structs.swift */, ); path = Models; sourceTree = ""; @@ -233,6 +308,153 @@ path = Requests; sourceTree = ""; }; + 65898B062AF363D4000930F6 /* StatUserPage */ = { + isa = PBXGroup; + children = ( + A226A8702ACFF2BA00E782E3 /* StatisticsUserProfileViewController.swift */, + A226A87A2ACFF78900E782E3 /* StatisticsUserProfileModel.swift */, + 65898B042AF36138000930F6 /* StatisticsUserProfileViewModel.swift */, + ); + path = StatUserPage; + sourceTree = ""; + }; + 65898B072AF363E9000930F6 /* StatUserCollection */ = { + isa = PBXGroup; + children = ( + A3F9D6212AF39E5400F66038 /* Model */, + A3F9D6202AF39E4100F66038 /* ViewModel */, + A3F9D61F2AF39E3200F66038 /* View */, + 65898B0A2AF365D9000930F6 /* RatingStackView.swift */, + 65898B122AF36721000930F6 /* UIBlockingProgressHUD.swift */, + ); + path = StatUserCollection; + sourceTree = ""; + }; + 65898B142AF36748000930F6 /* StatUserView */ = { + isa = PBXGroup; + children = ( + A3F9D61C2AF3980A00F66038 /* WebKit */, + A3F9D60A2AF390C000F66038 /* Model */, + A3F9D6092AF390A600F66038 /* ViewModel */, + A3F9D6002AF3900A00F66038 /* StatisticsViewController.swift */, + A3F9D6082AF3909000F66038 /* StatisticsTableView */, + ); + path = StatUserView; + sourceTree = ""; + }; + A226A8692ACFECE500E782E3 /* Catalog */ = { + isa = PBXGroup; + children = ( + A226A86A2ACFECE500E782E3 /* CatalogViewController.swift */, + A226A8762ACFF72500E782E3 /* CatalogViewModel.swift */, + ); + path = Catalog; + sourceTree = ""; + }; + A226A86C2ACFF1F000E782E3 /* ShoppingCart */ = { + isa = PBXGroup; + children = ( + A226A86E2ACFF2A900E782E3 /* ShoppingCartViewController.swift */, + A226A8782ACFF76900E782E3 /* ShoppingCartViewModel.swift */, + ); + path = ShoppingCart; + sourceTree = ""; + }; + A226A86D2ACFF27B00E782E3 /* Statistics */ = { + isa = PBXGroup; + children = ( + A3F9D6132AF391EF00F66038 /* Extentions */, + 65898B142AF36748000930F6 /* StatUserView */, + 65898B072AF363E9000930F6 /* StatUserCollection */, + 65898B062AF363D4000930F6 /* StatUserPage */, + A3F9D5FE2AF38B0500F66038 /* StatisticsRouter.swift */, + ); + path = Statistics; + sourceTree = ""; + }; + A2D5203B2ACF2B070083FAA7 /* Profile */ = { + isa = PBXGroup; + children = ( + A2D5203C2ACF2B210083FAA7 /* ProfileViewController.swift */, + A226A8742ACFF69B00E782E3 /* ProfileViewModel.swift */, + ); + path = Profile; + sourceTree = ""; + }; + A3F9D6082AF3909000F66038 /* StatisticsTableView */ = { + isa = PBXGroup; + children = ( + A3F9D6022AF3903000F66038 /* StatisticsTableViewCell.swift */, + A3F9D6042AF3905300F66038 /* ProfileCellView.swift */, + A3F9D6062AF3906900F66038 /* StatisticsTableViewCellModel.swift */, + ); + path = StatisticsTableView; + sourceTree = ""; + }; + A3F9D6092AF390A600F66038 /* ViewModel */ = { + isa = PBXGroup; + children = ( + A3F9D60F2AF3916500F66038 /* StatisticsViewModel.swift */, + A3F9D6112AF3917E00F66038 /* UserModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + A3F9D60A2AF390C000F66038 /* Model */ = { + isa = PBXGroup; + children = ( + A3F9D60B2AF390DE00F66038 /* ServerUserModel.swift */, + A3F9D60D2AF3910100F66038 /* StatisticsLoader.swift */, + ); + path = Model; + sourceTree = ""; + }; + A3F9D6132AF391EF00F66038 /* Extentions */ = { + isa = PBXGroup; + children = ( + A3F9D6142AF3921100F66038 /* Observable.swift */, + A3F9D6162AF3932E00F66038 /* EndPoint.swift */, + A3F9D6182AF3962500F66038 /* UIView+Layout.swift */, + A3F9D61A2AF397BC00F66038 /* GeometricParams.swift */, + ); + path = Extentions; + sourceTree = ""; + }; + A3F9D61C2AF3980A00F66038 /* WebKit */ = { + isa = PBXGroup; + children = ( + A3F9D61D2AF3981500F66038 /* WebKit.swift */, + ); + path = WebKit; + sourceTree = ""; + }; + A3F9D61F2AF39E3200F66038 /* View */ = { + isa = PBXGroup; + children = ( + A3F9D6282AF39EB700F66038 /* StatisticsUserNFTCollectionViewController.swift */, + A3F9D62A2AF39ECE00F66038 /* StatisticsUserNFTCollectionViewCell.swift */, + A3F9D62C2AF39EE400F66038 /* StatisticsUserNFTCollectionCellModel.swift */, + ); + path = View; + sourceTree = ""; + }; + A3F9D6202AF39E4100F66038 /* ViewModel */ = { + isa = PBXGroup; + children = ( + A3F9D6262AF39EA000F66038 /* StatisticsUserNFTCollectionViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + A3F9D6212AF39E5400F66038 /* Model */ = { + isa = PBXGroup; + children = ( + A3F9D6222AF39E6A00F66038 /* StatisticsNFTModel.swift */, + A3F9D6242AF39E8100F66038 /* StatisticsUserNFTCollectionModel.swift */, + ); + path = Model; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -346,7 +568,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3FC8C39729D24D9D0081F015 /* .swiftlint.yml in Resources */, 3F6806A329CBBAF200B4F915 /* LaunchScreen.storyboard in Resources */, 3F6806A029CBBAF200B4F915 /* Assets.xcassets in Resources */, 3F68069E29CBBAF100B4F915 /* Main.storyboard in Resources */, @@ -396,18 +617,53 @@ buildActionMask = 2147483647; files = ( 3FC8C38B29D242E90081F015 /* ProductDetailsTableViewCell.swift in Sources */, + A226A8752ACFF69B00E782E3 /* ProfileViewModel.swift in Sources */, + A3F9D5FF2AF38B0500F66038 /* StatisticsRouter.swift in Sources */, + A3F9D61E2AF3981500F66038 /* WebKit.swift in Sources */, + A3F9D62D2AF39EE400F66038 /* StatisticsUserNFTCollectionCellModel.swift in Sources */, + A3F9D6102AF3916500F66038 /* StatisticsViewModel.swift in Sources */, + A226A8792ACFF76900E782E3 /* ShoppingCartViewModel.swift in Sources */, 3F478ECF29DB474E00F6D39E /* Colors.swift in Sources */, + A3F9D60E2AF3910100F66038 /* StatisticsLoader.swift in Sources */, + A3F9D6252AF39E8100F66038 /* StatisticsUserNFTCollectionModel.swift in Sources */, + A3F9D6122AF3917E00F66038 /* UserModel.swift in Sources */, 3F478ED129DB476500F6D39E /* Fonts.swift in Sources */, + 65898B032AF36085000930F6 /* Models&Structs.swift in Sources */, + A3F9D6152AF3921100F66038 /* Observable.swift in Sources */, + A3F9D6232AF39E6B00F66038 /* StatisticsNFTModel.swift in Sources */, + A3F9D6012AF3900A00F66038 /* StatisticsViewController.swift in Sources */, + 65898B012AF3604A000930F6 /* Config.swift in Sources */, + A226A8732ACFF4B500E782E3 /* TabBarController.swift in Sources */, 3FC8C39329D246BA0081F015 /* DateFormatters+Presets.swift in Sources */, + A3F9D6172AF3932E00F66038 /* EndPoint.swift in Sources */, + A3F9D6272AF39EA000F66038 /* StatisticsUserNFTCollectionViewModel.swift in Sources */, + A226A86B2ACFECE500E782E3 /* CatalogViewController.swift in Sources */, + A3F9D6072AF3906900F66038 /* StatisticsTableViewCellModel.swift in Sources */, + A2D5203D2ACF2B210083FAA7 /* ProfileViewController.swift in Sources */, + A226A8772ACFF72500E782E3 /* CatalogViewModel.swift in Sources */, 3F68069B29CBBAF100B4F915 /* ProductDetailsTableViewController.swift in Sources */, + A226A8712ACFF2BA00E782E3 /* StatisticsUserProfileViewController.swift in Sources */, 3F6806D529CBBEC700B4F915 /* NetworkTask.swift in Sources */, 3F68069729CBBAF100B4F915 /* AppDelegate.swift in Sources */, + A3F9D60C2AF390DE00F66038 /* ServerUserModel.swift in Sources */, 3F68069929CBBAF100B4F915 /* SceneDelegate.swift in Sources */, + A3F9D6192AF3962500F66038 /* UIView+Layout.swift in Sources */, + 65898B132AF36721000930F6 /* UIBlockingProgressHUD.swift in Sources */, + A226A87B2ACFF78900E782E3 /* StatisticsUserProfileModel.swift in Sources */, + A3F9D6292AF39EB700F66038 /* StatisticsUserNFTCollectionViewController.swift in Sources */, + A3F9D6052AF3905300F66038 /* ProfileCellView.swift in Sources */, 3FC8C39129D2453B0081F015 /* ExampleRequest.swift in Sources */, + A3F9D62B2AF39ECE00F66038 /* StatisticsUserNFTCollectionViewCell.swift in Sources */, + A3F9D6032AF3903000F66038 /* StatisticsTableViewCell.swift in Sources */, 3F6806D729CBC50A00B4F915 /* CellsReusingUtils.swift in Sources */, 3F6806D329CBBE9600B4F915 /* NetworkRequest.swift in Sources */, 3F6806CB29CBBCC700B4F915 /* ExampleNetworkModel.swift in Sources */, + 65898B052AF36138000930F6 /* StatisticsUserProfileViewModel.swift in Sources */, + A226A86F2ACFF2A900E782E3 /* ShoppingCartViewController.swift in Sources */, 3F6806D129CBBE6B00B4F915 /* NetworkClient.swift in Sources */, + A3F9D61B2AF397BC00F66038 /* GeometricParams.swift in Sources */, + 65898B0B2AF365D9000930F6 /* RatingStackView.swift in Sources */, + 65898AFF2AF36012000930F6 /* User.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/andreikashin.xcuserdatad/UserInterfaceState.xcuserstate b/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/andreikashin.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000..fcc957b0c5 Binary files /dev/null and b/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/andreikashin.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/konstantinzuykov.xcuserdatad/UserInterfaceState.xcuserstate b/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/konstantinzuykov.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000..5b7ab81eae Binary files /dev/null and b/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/konstantinzuykov.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/noname.xcuserdatad/UserInterfaceState.xcuserstate b/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/noname.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000..f215e11175 Binary files /dev/null and b/FakeNFT.xcodeproj/project.xcworkspace/xcuserdata/noname.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/FakeNFT.xcodeproj/xcuserdata/andreikashin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/FakeNFT.xcodeproj/xcuserdata/andreikashin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000000..e8737f469e --- /dev/null +++ b/FakeNFT.xcodeproj/xcuserdata/andreikashin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/FakeNFT.xcodeproj/xcuserdata/andreikashin.xcuserdatad/xcschemes/xcschememanagement.plist b/FakeNFT.xcodeproj/xcuserdata/andreikashin.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000000..5c85bfcd81 --- /dev/null +++ b/FakeNFT.xcodeproj/xcuserdata/andreikashin.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + FakeNFT.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/FakeNFT.xcodeproj/xcuserdata/konstantinzuykov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/FakeNFT.xcodeproj/xcuserdata/konstantinzuykov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000000..c8ea7cd07b --- /dev/null +++ b/FakeNFT.xcodeproj/xcuserdata/konstantinzuykov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FakeNFT.xcodeproj/xcuserdata/konstantinzuykov.xcuserdatad/xcschemes/xcschememanagement.plist b/FakeNFT.xcodeproj/xcuserdata/konstantinzuykov.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000000..5c85bfcd81 --- /dev/null +++ b/FakeNFT.xcodeproj/xcuserdata/konstantinzuykov.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + FakeNFT.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/FakeNFT.xcodeproj/xcuserdata/noname.xcuserdatad/xcschemes/xcschememanagement.plist b/FakeNFT.xcodeproj/xcuserdata/noname.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000000..5c85bfcd81 --- /dev/null +++ b/FakeNFT.xcodeproj/xcuserdata/noname.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + FakeNFT.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/FakeNFT/.DS_Store b/FakeNFT/.DS_Store new file mode 100644 index 0000000000..40587e5e9d Binary files /dev/null and b/FakeNFT/.DS_Store differ diff --git a/FakeNFT/Assets.xcassets/AccentColor.colorset/Contents.json b/FakeNFT/Assets.xcassets/AccentColor.colorset/Contents.json index eb87897008..97650a1a6e 100644 --- a/FakeNFT/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/FakeNFT/Assets.xcassets/AccentColor.colorset/Contents.json @@ -1,6 +1,15 @@ { "colors" : [ { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, "idiom" : "universal" } ], diff --git a/FakeNFT/Assets.xcassets/AppIcon.appiconset/Contents.json b/FakeNFT/Assets.xcassets/AppIcon.appiconset/Contents.json index 13613e3ee1..ef6fe48578 100644 --- a/FakeNFT/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/FakeNFT/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,6 +1,7 @@ { "images" : [ { + "filename" : "FakeNFT (YP).png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/FakeNFT/Assets.xcassets/AppIcon.appiconset/FakeNFT (YP).png b/FakeNFT/Assets.xcassets/AppIcon.appiconset/FakeNFT (YP).png new file mode 100644 index 0000000000..8bc289db57 Binary files /dev/null and b/FakeNFT/Assets.xcassets/AppIcon.appiconset/FakeNFT (YP).png differ diff --git a/FakeNFT/Assets.xcassets/Cart/Contents.json b/FakeNFT/Assets.xcassets/Cart/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Cart/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Cart/cart.imageset/Contents.json b/FakeNFT/Assets.xcassets/Cart/cart.imageset/Contents.json new file mode 100644 index 0000000000..707a802248 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Cart/cart.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "card.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Frame.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Cart/cart.imageset/Frame.pdf b/FakeNFT/Assets.xcassets/Cart/cart.imageset/Frame.pdf new file mode 100644 index 0000000000..b0d0820679 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Cart/cart.imageset/Frame.pdf differ diff --git a/FakeNFT/Assets.xcassets/Cart/cart.imageset/card.pdf b/FakeNFT/Assets.xcassets/Cart/cart.imageset/card.pdf new file mode 100644 index 0000000000..af5c7e7775 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Cart/cart.imageset/card.pdf differ diff --git a/FakeNFT/Assets.xcassets/Cart/inCart.imageset/Contents.json b/FakeNFT/Assets.xcassets/Cart/inCart.imageset/Contents.json new file mode 100644 index 0000000000..7f2ca78134 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Cart/inCart.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "inCard.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Frame.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Cart/inCart.imageset/Frame.pdf b/FakeNFT/Assets.xcassets/Cart/inCart.imageset/Frame.pdf new file mode 100644 index 0000000000..8781de00fb Binary files /dev/null and b/FakeNFT/Assets.xcassets/Cart/inCart.imageset/Frame.pdf differ diff --git a/FakeNFT/Assets.xcassets/Cart/inCart.imageset/inCard.pdf b/FakeNFT/Assets.xcassets/Cart/inCart.imageset/inCard.pdf new file mode 100644 index 0000000000..a34f2fe6d1 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Cart/inCart.imageset/inCard.pdf differ diff --git a/FakeNFT/Assets.xcassets/Colors/Contents.json b/FakeNFT/Assets.xcassets/Colors/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Colors/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Colors/background.colorset/Contents.json b/FakeNFT/Assets.xcassets/Colors/background.colorset/Contents.json new file mode 100644 index 0000000000..2566fd83fe --- /dev/null +++ b/FakeNFT/Assets.xcassets/Colors/background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.135", + "green" : "0.108", + "red" : "0.103" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Colors/ypBlack.colorset/Contents.json b/FakeNFT/Assets.xcassets/Colors/ypBlack.colorset/Contents.json new file mode 100644 index 0000000000..d955cf9bdc --- /dev/null +++ b/FakeNFT/Assets.xcassets/Colors/ypBlack.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.135", + "green" : "0.108", + "red" : "0.101" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Colors/ypBlue.colorset/Contents.json b/FakeNFT/Assets.xcassets/Colors/ypBlue.colorset/Contents.json new file mode 100644 index 0000000000..ab3396538d --- /dev/null +++ b/FakeNFT/Assets.xcassets/Colors/ypBlue.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.989", + "green" : "0.518", + "red" : "0.042" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.989", + "green" : "0.518", + "red" : "0.042" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Colors/ypGreen.colorset/Contents.json b/FakeNFT/Assets.xcassets/Colors/ypGreen.colorset/Contents.json new file mode 100644 index 0000000000..081b22ef64 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Colors/ypGreen.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.105", + "green" : "0.625", + "red" : "0.108" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.105", + "green" : "0.625", + "red" : "0.108" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Colors/ypLightGrey.colorset/Contents.json b/FakeNFT/Assets.xcassets/Colors/ypLightGrey.colorset/Contents.json new file mode 100644 index 0000000000..a19eb0b74e --- /dev/null +++ b/FakeNFT/Assets.xcassets/Colors/ypLightGrey.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.972", + "green" : "0.969", + "red" : "0.969" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.178", + "green" : "0.173", + "red" : "0.173" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Colors/ypRed.colorset/Contents.json b/FakeNFT/Assets.xcassets/Colors/ypRed.colorset/Contents.json new file mode 100644 index 0000000000..98c2b8ffe4 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Colors/ypRed.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.425", + "green" : "0.421", + "red" : "0.961" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.425", + "green" : "0.421", + "red" : "0.961" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Colors/ypWhite.colorset/Contents.json b/FakeNFT/Assets.xcassets/Colors/ypWhite.colorset/Contents.json new file mode 100644 index 0000000000..4f67351a19 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Colors/ypWhite.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.135", + "green" : "0.108", + "red" : "0.101" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE).png b/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE).png new file mode 100644 index 0000000000..35759927cf Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE).png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE)@2x.png b/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE)@2x.png new file mode 100644 index 0000000000..4d2b3abded Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE)@2x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE)@3x.png b/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE)@3x.png new file mode 100644 index 0000000000..050d308d26 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/ApeCoin (APE)@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/Contents.json new file mode 100644 index 0000000000..5ffaaaff70 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Apecoin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "ApeCoin (APE).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "ApeCoin (APE)@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "ApeCoin (APE)@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC).png b/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC).png new file mode 100644 index 0000000000..48b65549c5 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC).png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC)@2x.png b/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC)@2x.png new file mode 100644 index 0000000000..51dc373d78 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC)@2x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC)@3x.png b/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC)@3x.png new file mode 100644 index 0000000000..01d91a0d77 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Bitcoin (BTC)@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Contents.json new file mode 100644 index 0000000000..f4fa540d39 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Bitcoin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Bitcoin (BTC).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Bitcoin (BTC)@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Bitcoin (BTC)@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA).png b/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA).png new file mode 100644 index 0000000000..0e427e691c Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA).png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA)@2x.png b/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA)@2x.png new file mode 100644 index 0000000000..10fb404c4c Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA)@2x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA)@3x.png b/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA)@3x.png new file mode 100644 index 0000000000..19684c978d Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Cardano (ADA)@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Contents.json new file mode 100644 index 0000000000..92bbc883d5 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Cardano.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Cardano (ADA).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Cardano (ADA)@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Cardano (ADA)@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Contents.json new file mode 100644 index 0000000000..22d44424c6 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Dogecoin (DOGE).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Dogecoin (DOGE)@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Dogecoin (DOGE)@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE).png b/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE).png new file mode 100644 index 0000000000..d374c41e47 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE).png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE)@2x.png b/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE)@2x.png new file mode 100644 index 0000000000..3eb1e9881e Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE)@2x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE)@3x.png b/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE)@3x.png new file mode 100644 index 0000000000..842d606522 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Dogecoin.imageset/Dogecoin (DOGE)@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Contents.json new file mode 100644 index 0000000000..eb88c213c2 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Ethereum (ETH).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Ethereum (ETH)@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Ethereum (ETH)@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH).png b/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH).png new file mode 100644 index 0000000000..dc1991af51 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH).png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH)@2x.png b/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH)@2x.png new file mode 100644 index 0000000000..384f8bd0ce Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH)@2x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH)@3x.png b/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH)@3x.png new file mode 100644 index 0000000000..05101c00fd Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Ethereum.imageset/Ethereum (ETH)@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Contents.json new file mode 100644 index 0000000000..71c1cbe47e --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Shiba Inu (SHIB).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Shiba Inu (SHIB)@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Shiba Inu (SHIB)@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB).png b/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB).png new file mode 100644 index 0000000000..a9ed44f936 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB).png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB)@2x.png b/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB)@2x.png new file mode 100644 index 0000000000..852d2b837d Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB)@2x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB)@3x.png b/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB)@3x.png new file mode 100644 index 0000000000..507f5455f4 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Shiba Inu.imageset/Shiba Inu (SHIB)@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Contents.json new file mode 100644 index 0000000000..86a619c5da --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Solana (SOL).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Solana (SOL)@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Solana (SOL)@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL).png b/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL).png new file mode 100644 index 0000000000..e6d512d762 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL).png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL)@2x.png b/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL)@2x.png new file mode 100644 index 0000000000..c68dd4c2e5 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL)@2x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL)@3x.png b/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL)@3x.png new file mode 100644 index 0000000000..ecfceab415 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Solana.imageset/Solana (SOL)@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Contents.json b/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Contents.json new file mode 100644 index 0000000000..293e680c99 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Tether (USDT).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Tether (USDT)@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Tether (USDT)@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT).png b/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT).png new file mode 100644 index 0000000000..c77c6289df Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT).png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT)@2x.png b/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT)@2x.png new file mode 100644 index 0000000000..96d3c1acfc Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT)@2x.png differ diff --git a/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT)@3x.png b/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT)@3x.png new file mode 100644 index 0000000000..390f5d86cc Binary files /dev/null and b/FakeNFT/Assets.xcassets/Crypto/Tether.imageset/Tether (USDT)@3x.png differ diff --git a/FakeNFT/Assets.xcassets/EditPofile/Contents.json b/FakeNFT/Assets.xcassets/EditPofile/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/EditPofile/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Contents.json b/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Contents.json new file mode 100644 index 0000000000..51543638aa --- /dev/null +++ b/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "Dark.png", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Dark 1.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Dark 1.png b/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Dark 1.png new file mode 100644 index 0000000000..174de9cd51 Binary files /dev/null and b/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Dark 1.png differ diff --git a/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Dark.png b/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Dark.png new file mode 100644 index 0000000000..b22bd6dfff Binary files /dev/null and b/FakeNFT/Assets.xcassets/EditPofile/editProfile.imageset/Dark.png differ diff --git a/FakeNFT/Assets.xcassets/LaunchScreenLogo/Contents.json b/FakeNFT/Assets.xcassets/LaunchScreenLogo/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/LaunchScreenLogo/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Contents.json b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Contents.json new file mode 100644 index 0000000000..1696f74725 --- /dev/null +++ b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Contents.json @@ -0,0 +1,56 @@ +{ + "images" : [ + { + "filename" : "Vector@1x.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Vector@1x 1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Vector@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Vector@2x 1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Vector@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Vector@3x 1.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@1x 1.png b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@1x 1.png new file mode 100644 index 0000000000..3edf41ee68 Binary files /dev/null and b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@1x 1.png differ diff --git a/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@1x.png b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@1x.png new file mode 100644 index 0000000000..84c2c4b1a4 Binary files /dev/null and b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@1x.png differ diff --git a/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@2x 1.png b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@2x 1.png new file mode 100644 index 0000000000..a2790e6e54 Binary files /dev/null and b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@2x 1.png differ diff --git a/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@2x.png b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@2x.png new file mode 100644 index 0000000000..20bf0e7379 Binary files /dev/null and b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@2x.png differ diff --git a/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@3x 1.png b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@3x 1.png new file mode 100644 index 0000000000..fd9bc0a587 Binary files /dev/null and b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@3x 1.png differ diff --git a/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@3x.png b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@3x.png new file mode 100644 index 0000000000..7ff389dc54 Binary files /dev/null and b/FakeNFT/Assets.xcassets/LaunchScreenLogo/logo.imageset/Vector@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Like/Contents.json b/FakeNFT/Assets.xcassets/Like/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Like/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Like/Like.imageset/Contents.json b/FakeNFT/Assets.xcassets/Like/Like.imageset/Contents.json new file mode 100644 index 0000000000..3ae79fd445 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Like/Like.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "like.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Like/Like.imageset/like.pdf b/FakeNFT/Assets.xcassets/Like/Like.imageset/like.pdf new file mode 100644 index 0000000000..cbfb484cd6 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Like/Like.imageset/like.pdf differ diff --git a/FakeNFT/Assets.xcassets/Like/dislike.imageset/Contents.json b/FakeNFT/Assets.xcassets/Like/dislike.imageset/Contents.json new file mode 100644 index 0000000000..110025a069 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Like/dislike.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "dislike.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Like/dislike.imageset/dislike.pdf b/FakeNFT/Assets.xcassets/Like/dislike.imageset/dislike.pdf new file mode 100644 index 0000000000..e98a1e020d Binary files /dev/null and b/FakeNFT/Assets.xcassets/Like/dislike.imageset/dislike.pdf differ diff --git a/FakeNFT/Assets.xcassets/MockNFT/Contents.json b/FakeNFT/Assets.xcassets/MockNFT/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/MockNFT/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/Contents.json b/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/Contents.json new file mode 100644 index 0000000000..d3f2433300 --- /dev/null +++ b/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "NFT card.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "NFT card@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "NFT card@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card.png b/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card.png new file mode 100644 index 0000000000..086965ee5c Binary files /dev/null and b/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card.png differ diff --git a/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card@2x.png b/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card@2x.png new file mode 100644 index 0000000000..4b3e38d9c7 Binary files /dev/null and b/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card@2x.png differ diff --git a/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card@3x.png b/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card@3x.png new file mode 100644 index 0000000000..04d8e6ba7c Binary files /dev/null and b/FakeNFT/Assets.xcassets/MockNFT/NFT1.imageset/NFT card@3x.png differ diff --git a/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/Contents.json b/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/Contents.json new file mode 100644 index 0000000000..1b54793f66 --- /dev/null +++ b/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "NFT card2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "NFT card@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "NFT card@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card2.png b/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card2.png new file mode 100644 index 0000000000..044d58ae6d Binary files /dev/null and b/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card2.png differ diff --git a/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card@2x.png b/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card@2x.png new file mode 100644 index 0000000000..69d3f1d252 Binary files /dev/null and b/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card@2x.png differ diff --git a/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card@3x.png b/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card@3x.png new file mode 100644 index 0000000000..9250488f40 Binary files /dev/null and b/FakeNFT/Assets.xcassets/MockNFT/NFT2.imageset/NFT card@3x.png differ diff --git a/FakeNFT/Assets.xcassets/NavBarImages/Contents.json b/FakeNFT/Assets.xcassets/NavBarImages/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/NavBarImages/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/Contents.json b/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/Contents.json new file mode 100644 index 0000000000..5cbe9c25f9 --- /dev/null +++ b/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "sortButton.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "Light.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/Light.pdf b/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/Light.pdf new file mode 100644 index 0000000000..da1724fa0e Binary files /dev/null and b/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/Light.pdf differ diff --git a/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/sortButton.pdf b/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/sortButton.pdf new file mode 100644 index 0000000000..4d715f2ae7 Binary files /dev/null and b/FakeNFT/Assets.xcassets/NavBarImages/sortButton.imageset/sortButton.pdf differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/Contents.json b/FakeNFT/Assets.xcassets/OnboardingImages/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/OnboardingImages/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Contents.json b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Contents.json new file mode 100644 index 0000000000..13a51e48e4 --- /dev/null +++ b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Rectangle 158.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Rectangle 158@3x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Rectangle 158@3x 1.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158.png new file mode 100644 index 0000000000..d76063760e Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158@3x 1.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158@3x 1.png new file mode 100644 index 0000000000..95afa2357d Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158@3x 1.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158@3x.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158@3x.png new file mode 100644 index 0000000000..95afa2357d Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_gradient.imageset/Rectangle 158@3x.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/Contents.json b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/Contents.json new file mode 100644 index 0000000000..fbcea5d9a4 --- /dev/null +++ b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "image 15.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "image 15@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "image 15@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15.png new file mode 100644 index 0000000000..901712bdd7 Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15@2x.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15@2x.png new file mode 100644 index 0000000000..71e02aec1e Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15@2x.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15@3x.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15@3x.png new file mode 100644 index 0000000000..4a15b84a28 Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_1.imageset/image 15@3x.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/Contents.json b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/Contents.json new file mode 100644 index 0000000000..6afaf6af29 --- /dev/null +++ b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "image 14.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "image 14@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "image 14@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14.png new file mode 100644 index 0000000000..e30eeacad5 Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14@2x.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14@2x.png new file mode 100644 index 0000000000..b9ae698eca Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14@2x.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14@3x.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14@3x.png new file mode 100644 index 0000000000..a33c70a26a Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_2.imageset/image 14@3x.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/Contents.json b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/Contents.json new file mode 100644 index 0000000000..0d3ff20f48 --- /dev/null +++ b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "image 16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "image 16@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "image 16@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16.png new file mode 100644 index 0000000000..73915a1d5c Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16@2x.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16@2x.png new file mode 100644 index 0000000000..810e98041f Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16@2x.png differ diff --git a/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16@3x.png b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16@3x.png new file mode 100644 index 0000000000..18da45a6ff Binary files /dev/null and b/FakeNFT/Assets.xcassets/OnboardingImages/onboarding_image_3.imageset/image 16@3x.png differ diff --git a/FakeNFT/Assets.xcassets/Stars/Contents.json b/FakeNFT/Assets.xcassets/Stars/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Stars/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Stars/star.imageset/Contents.json b/FakeNFT/Assets.xcassets/Stars/star.imageset/Contents.json new file mode 100644 index 0000000000..ecd1c02458 --- /dev/null +++ b/FakeNFT/Assets.xcassets/Stars/star.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "star.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "No Active.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Stars/star.imageset/No Active.pdf b/FakeNFT/Assets.xcassets/Stars/star.imageset/No Active.pdf new file mode 100644 index 0000000000..da875eaf66 Binary files /dev/null and b/FakeNFT/Assets.xcassets/Stars/star.imageset/No Active.pdf differ diff --git a/FakeNFT/Assets.xcassets/Stars/star.imageset/star.pdf b/FakeNFT/Assets.xcassets/Stars/star.imageset/star.pdf new file mode 100644 index 0000000000..437ad38cbe Binary files /dev/null and b/FakeNFT/Assets.xcassets/Stars/star.imageset/star.pdf differ diff --git a/FakeNFT/Assets.xcassets/Stars/star_yellow.imageset/Contents.json b/FakeNFT/Assets.xcassets/Stars/star_yellow.imageset/Contents.json new file mode 100644 index 0000000000..80f8fb058b --- /dev/null +++ b/FakeNFT/Assets.xcassets/Stars/star_yellow.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "star_yellow.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/Stars/star_yellow.imageset/star_yellow.pdf b/FakeNFT/Assets.xcassets/Stars/star_yellow.imageset/star_yellow.pdf new file mode 100644 index 0000000000..08888961ea Binary files /dev/null and b/FakeNFT/Assets.xcassets/Stars/star_yellow.imageset/star_yellow.pdf differ diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Contents.json b/FakeNFT/Assets.xcassets/StatisticsTabImages/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/StatisticsTabImages/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/Contents.json b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFive.imageset/Contents.json b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFive.imageset/Contents.json new file mode 100644 index 0000000000..8bb7c80ceb --- /dev/null +++ b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFive.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "propertyFive.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFive.imageset/propertyFive.png b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFive.imageset/propertyFive.png new file mode 100644 index 0000000000..40eb6512fc Binary files /dev/null and b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFive.imageset/propertyFive.png differ diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFour.imageset/Contents.json b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFour.imageset/Contents.json new file mode 100644 index 0000000000..ea6e3e05a8 --- /dev/null +++ b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFour.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "propertyFour.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFour.imageset/propertyFour.png b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFour.imageset/propertyFour.png new file mode 100644 index 0000000000..ad78c27e09 Binary files /dev/null and b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyFour.imageset/propertyFour.png differ diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyOne.imageset/Contents.json b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyOne.imageset/Contents.json new file mode 100644 index 0000000000..143ec55cca --- /dev/null +++ b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyOne.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "propertyOne.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyOne.imageset/propertyOne.png b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyOne.imageset/propertyOne.png new file mode 100644 index 0000000000..cea10328a7 Binary files /dev/null and b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyOne.imageset/propertyOne.png differ diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyThree.imageset/Contents.json b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyThree.imageset/Contents.json new file mode 100644 index 0000000000..dc23f43905 --- /dev/null +++ b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyThree.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "propertyThree.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyThree.imageset/propertyThree.png b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyThree.imageset/propertyThree.png new file mode 100644 index 0000000000..7eae6a092b Binary files /dev/null and b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyThree.imageset/propertyThree.png differ diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyTwo.imageset/Contents.json b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyTwo.imageset/Contents.json new file mode 100644 index 0000000000..c8325eab0c --- /dev/null +++ b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyTwo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "propertyTwo.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyTwo.imageset/propertyTwo.png b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyTwo.imageset/propertyTwo.png new file mode 100644 index 0000000000..e4661f296e Binary files /dev/null and b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyTwo.imageset/propertyTwo.png differ diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyZero.imageset/Contents.json b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyZero.imageset/Contents.json new file mode 100644 index 0000000000..cb551fbcb7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyZero.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "propertyZero.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyZero.imageset/propertyZero.png b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyZero.imageset/propertyZero.png new file mode 100644 index 0000000000..00366163ba Binary files /dev/null and b/FakeNFT/Assets.xcassets/StatisticsTabImages/Rating/propertyZero.imageset/propertyZero.png differ diff --git a/FakeNFT/Assets.xcassets/placeholder-avatar.imageset/Contents.json b/FakeNFT/Assets.xcassets/placeholder-avatar.imageset/Contents.json new file mode 100644 index 0000000000..274fb693de --- /dev/null +++ b/FakeNFT/Assets.xcassets/placeholder-avatar.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Userpick.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/placeholder-avatar.imageset/Userpick.svg b/FakeNFT/Assets.xcassets/placeholder-avatar.imageset/Userpick.svg new file mode 100644 index 0000000000..3180d3cb91 --- /dev/null +++ b/FakeNFT/Assets.xcassets/placeholder-avatar.imageset/Userpick.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/FakeNFT/Assets.xcassets/tabBarImages/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageActive.imageset/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageActive.imageset/Contents.json new file mode 100644 index 0000000000..98e28f3b94 --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageActive.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "cartTabBarImageActive.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageActive.imageset/cartTabBarImageActive.pdf b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageActive.imageset/cartTabBarImageActive.pdf new file mode 100644 index 0000000000..937c6378c8 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageActive.imageset/cartTabBarImageActive.pdf differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/Contents.json new file mode 100644 index 0000000000..5b38dbed39 --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "cartTabBarImageNoActive.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "No Active.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/No Active.png b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/No Active.png new file mode 100644 index 0000000000..8caf61009c Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/No Active.png differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/cartTabBarImageNoActive.pdf b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/cartTabBarImageNoActive.pdf new file mode 100644 index 0000000000..6cb73e606c Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/cartTabBarImageNoActive.imageset/cartTabBarImageNoActive.pdf differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageActive.imageset/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageActive.imageset/Contents.json new file mode 100644 index 0000000000..8c65c2b42a --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageActive.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "catalogTabBarImageActive.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageActive.imageset/catalogTabBarImageActive.pdf b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageActive.imageset/catalogTabBarImageActive.pdf new file mode 100644 index 0000000000..31cef700e0 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageActive.imageset/catalogTabBarImageActive.pdf differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/Contents.json new file mode 100644 index 0000000000..9d60be4f08 --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "catalogTabBarImageNoActive.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "person.crop.rectangle.stack.fill.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/catalogTabBarImageNoActive.pdf b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/catalogTabBarImageNoActive.pdf new file mode 100644 index 0000000000..a74c96d7d1 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/catalogTabBarImageNoActive.pdf differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/person.crop.rectangle.stack.fill.png b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/person.crop.rectangle.stack.fill.png new file mode 100644 index 0000000000..ab43d59eef Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/catalogTabBarImageNoActive.imageset/person.crop.rectangle.stack.fill.png differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageActive.imageset/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageActive.imageset/Contents.json new file mode 100644 index 0000000000..f2c21e6f58 --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageActive.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "profileTabBarImageActive.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageActive.imageset/profileTabBarImageActive.pdf b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageActive.imageset/profileTabBarImageActive.pdf new file mode 100644 index 0000000000..fbecb2a2c8 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageActive.imageset/profileTabBarImageActive.pdf differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/Contents.json new file mode 100644 index 0000000000..8f4e2cfcb3 --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "profileTabBarImageNoActive.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "No Active.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/No Active.png b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/No Active.png new file mode 100644 index 0000000000..dfd6416ea5 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/No Active.png differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/profileTabBarImageNoActive.pdf b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/profileTabBarImageNoActive.pdf new file mode 100644 index 0000000000..5b73833c71 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/profileTabBarImageNoActive.imageset/profileTabBarImageNoActive.pdf differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageActive.imageset/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageActive.imageset/Contents.json new file mode 100644 index 0000000000..8069e21af1 --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageActive.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "statisticsTabBarImageActive.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageActive.imageset/statisticsTabBarImageActive.pdf b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageActive.imageset/statisticsTabBarImageActive.pdf new file mode 100644 index 0000000000..d47f672942 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageActive.imageset/statisticsTabBarImageActive.pdf differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/Contents.json b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/Contents.json new file mode 100644 index 0000000000..4a6908733f --- /dev/null +++ b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "statisticsTabBarImageNoActive.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "flag.2.crossed.fill.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/flag.2.crossed.fill.png b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/flag.2.crossed.fill.png new file mode 100644 index 0000000000..aa5219bbc3 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/flag.2.crossed.fill.png differ diff --git a/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/statisticsTabBarImageNoActive.pdf b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/statisticsTabBarImageNoActive.pdf new file mode 100644 index 0000000000..80fbb03009 Binary files /dev/null and b/FakeNFT/Assets.xcassets/tabBarImages/statisticsTabBarImageNoActive.imageset/statisticsTabBarImageNoActive.pdf differ diff --git a/FakeNFT/Base.lproj/LaunchScreen.storyboard b/FakeNFT/Base.lproj/LaunchScreen.storyboard index 865e9329f3..224e8c8495 100644 --- a/FakeNFT/Base.lproj/LaunchScreen.storyboard +++ b/FakeNFT/Base.lproj/LaunchScreen.storyboard @@ -1,7 +1,10 @@ - - + + + - + + + @@ -11,15 +14,30 @@ - + - + + + + + + + + + + - + + + + + + + diff --git a/FakeNFT/Base.lproj/Main.storyboard b/FakeNFT/Base.lproj/Main.storyboard index 4fe9d52e59..4b9ada54df 100644 --- a/FakeNFT/Base.lproj/Main.storyboard +++ b/FakeNFT/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -35,7 +35,7 @@ - + @@ -159,9 +159,9 @@ + - - + diff --git a/FakeNFT/DesignSystem/Colors.swift b/FakeNFT/DesignSystem/Colors.swift index 685dff4b0d..2edd50df19 100644 --- a/FakeNFT/DesignSystem/Colors.swift +++ b/FakeNFT/DesignSystem/Colors.swift @@ -17,7 +17,12 @@ extension UIColor { default: (alpha, red, green, blue) = (255, 0, 0, 0) } - self.init(red: CGFloat(red) / 255, green: CGFloat(green) / 255, blue: CGFloat(blue) / 255, alpha: CGFloat(alpha) / 255) + self.init( + red: CGFloat(red) / 255, + green: CGFloat(green) / 255, + blue: CGFloat(blue) / 255, + alpha: CGFloat(alpha) / 255 + ) } // Ниже приведены примеры цветов, настоящие цвета надо взять из фигмы @@ -29,11 +34,23 @@ extension UIColor { static let secondary = UIColor(red: 255 / 255, green: 193 / 255, blue: 7 / 255, alpha: 1.0) // Background Colors - static let background = UIColor.white + static let background = UIColor(named: "background") + + // Colors + static let ypGreen = UIColor(named: "ypGreen") + static let ypLightGrey = UIColor(named: "ypLightGrey") + static let ypBlack = UIColor(named: "ypBlack") + static let ypBlue = UIColor(named: "ypBlue") + static let ypRed = UIColor(named: "ypRed") + static let ypWhite = UIColor(named: "ypWhite") // Text Colors - static let textPrimary = UIColor.black + static let textPrimary = UIColor(named: "ypBlack") ?? UIColor.black static let textSecondary = UIColor.gray static let textOnPrimary = UIColor.white - static let textOnSecondary = UIColor.black + + static let textOnSecondary = UIColor(named: "ypBlack") ?? UIColor.black + + static let tableViewBackground = UIColor(red: 0.902, green: 0.91, blue: 0.922, alpha: 0.3) + static let textFiledBackground = UIColor(red: 0.902, green: 0.91, blue: 0.922, alpha: 0.3) } diff --git a/FakeNFT/DesignSystem/Fonts.swift b/FakeNFT/DesignSystem/Fonts.swift index d8e1f6657d..0ed7d9c733 100644 --- a/FakeNFT/DesignSystem/Fonts.swift +++ b/FakeNFT/DesignSystem/Fonts.swift @@ -16,4 +16,6 @@ extension UIFont { // Caption Fonts static var caption1 = UIFont.systemFont(ofSize: 15, weight: .regular) static var caption2 = UIFont.systemFont(ofSize: 13, weight: .regular) + + static var medium10 = UIFont.systemFont(ofSize: 10, weight: .medium) } diff --git a/FakeNFT/Foundation/NetworkClient/NetworkRequest.swift b/FakeNFT/Foundation/NetworkClient/NetworkRequest.swift index bc7fa0ba39..02407f8900 100644 --- a/FakeNFT/Foundation/NetworkClient/NetworkRequest.swift +++ b/FakeNFT/Foundation/NetworkClient/NetworkRequest.swift @@ -18,3 +18,9 @@ extension NetworkRequest { var httpMethod: HttpMethod { .get } var dto: Encodable? { nil } } + +struct DefaultNetworkRequest: NetworkRequest { + let endpoint: URL? + let dto: Encodable? + let httpMethod: HttpMethod +} diff --git a/FakeNFT/Models/Config.swift b/FakeNFT/Models/Config.swift new file mode 100644 index 0000000000..1eab6f0c2c --- /dev/null +++ b/FakeNFT/Models/Config.swift @@ -0,0 +1,16 @@ +// +// Config.swift +// FakeNFT +// +// Created by Konstantin Zuykov on 02.11.2023. +// + +import Foundation + +struct Config { + static let mockOrderId = "1" + static let baseUrl = "https://64a03f83ed3c41bdd7a72309.mockapi.io/api/v1" + static let userAgreementUrl = "https://yandex.ru/legal/practicum_termsofuse" + static let usersSortTypeKey = "statistic:sortKey" + static let cartSortKey = "cart:sortKey" +} diff --git a/FakeNFT/Models/Models&Structs.swift b/FakeNFT/Models/Models&Structs.swift new file mode 100644 index 0000000000..9e2fa53800 --- /dev/null +++ b/FakeNFT/Models/Models&Structs.swift @@ -0,0 +1,34 @@ +// +// Models&Structs.swift +// FakeNFT +// +// Created by Konstantin Zuykov on 02.11.2023. +// + +import Foundation + +enum StatSortType: String { + case byName = "BYNAME" + case byRating = "BYRATING" +} + +struct Nft: Codable { + let createdAt: String + let name: String + let images: [String] + let rating: Int + let description: String + let price: Double + let id: String +} + +struct Request: NetworkRequest { + var endpoint: URL? + var queryParameters: [String: String]? + var httpMethod: HttpMethod +} + +enum SortAttribute { + case name + case nftCount +} diff --git a/FakeNFT/Models/User.swift b/FakeNFT/Models/User.swift new file mode 100644 index 0000000000..7cb6ef4e20 --- /dev/null +++ b/FakeNFT/Models/User.swift @@ -0,0 +1,18 @@ +// +// User.swift +// FakeNFT +// +// Created by Konstantin Zuykov on 02.11.2023. +// + +import Foundation + +struct User: Codable { + let avatar: String + let name: String + let description: String + let website: String + let nfts: [String] + let rating: String + let id: String +} diff --git a/FakeNFT/SceneDelegate.swift b/FakeNFT/SceneDelegate.swift index 90dc0c28df..65fd84f906 100644 --- a/FakeNFT/SceneDelegate.swift +++ b/FakeNFT/SceneDelegate.swift @@ -3,5 +3,11 @@ import UIKit final class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - func scene(_: UIScene, willConnectTo _: UISceneSession, options _: UIScene.ConnectionOptions) {} + func scene(_ scene: UIScene, willConnectTo _: UISceneSession, options _: UIScene.ConnectionOptions) { + guard let scene = (scene as? UIWindowScene) else { return } + + window = UIWindow(windowScene: scene) + window?.rootViewController = TabBarController() + window?.makeKeyAndVisible() + } } diff --git a/FakeNFT/Scenes /.DS_Store b/FakeNFT/Scenes /.DS_Store new file mode 100644 index 0000000000..d0fdf2e72f Binary files /dev/null and b/FakeNFT/Scenes /.DS_Store differ diff --git a/FakeNFT/Scenes /Catalog/CatalogViewController.swift b/FakeNFT/Scenes /Catalog/CatalogViewController.swift new file mode 100644 index 0000000000..e06cbf64fe --- /dev/null +++ b/FakeNFT/Scenes /Catalog/CatalogViewController.swift @@ -0,0 +1,12 @@ +// +// CatalogView.swift +// FakeNFT +// +// Created by Respect on 06.10.2023. +// + +import UIKit + +final class CatalogViewController: UIViewController { + var catalogViewModel: CatalogViewModel? +} diff --git a/FakeNFT/Scenes /Catalog/CatalogViewModel.swift b/FakeNFT/Scenes /Catalog/CatalogViewModel.swift new file mode 100644 index 0000000000..3c70efef2a --- /dev/null +++ b/FakeNFT/Scenes /Catalog/CatalogViewModel.swift @@ -0,0 +1,12 @@ +// +// CatalogViewModel.swift +// FakeNFT +// +// Created by Артем Кохан on 06.10.2023. +// + +import Foundation + +final class CatalogViewModel { + +} diff --git a/FakeNFT/Scenes /Profile/ProfileViewController.swift b/FakeNFT/Scenes /Profile/ProfileViewController.swift new file mode 100644 index 0000000000..7bf39797f5 --- /dev/null +++ b/FakeNFT/Scenes /Profile/ProfileViewController.swift @@ -0,0 +1,12 @@ +// +// ProfileViewController.swift +// FakeNFT +// +// Created by Артем Кохан on 05.10.2023. +// + +import UIKit + +final class ProfileViewController: UIViewController { + var profileViewModel: ProfileViewModel? +} diff --git a/FakeNFT/Scenes /Profile/ProfileViewModel.swift b/FakeNFT/Scenes /Profile/ProfileViewModel.swift new file mode 100644 index 0000000000..3e4d0b537f --- /dev/null +++ b/FakeNFT/Scenes /Profile/ProfileViewModel.swift @@ -0,0 +1,12 @@ +// +// ProfileViewModel.swift +// FakeNFT +// +// Created by Артем Кохан on 06.10.2023. +// + +import Foundation + +final class ProfileViewModel { + // +} diff --git a/FakeNFT/Scenes /ShoppingCart/ShoppingCartViewController.swift b/FakeNFT/Scenes /ShoppingCart/ShoppingCartViewController.swift new file mode 100644 index 0000000000..a64e369d93 --- /dev/null +++ b/FakeNFT/Scenes /ShoppingCart/ShoppingCartViewController.swift @@ -0,0 +1,12 @@ +// +// BasketViewController.swift +// FakeNFT +// +// Created by Артем Кохан on 06.10.2023. +// + +import UIKit + +final class ShoppingCartViewController: UIViewController { + var shoppingCartViewModel: ShoppingCartViewModel? +} diff --git a/FakeNFT/Scenes /ShoppingCart/ShoppingCartViewModel.swift b/FakeNFT/Scenes /ShoppingCart/ShoppingCartViewModel.swift new file mode 100644 index 0000000000..4c84aa4702 --- /dev/null +++ b/FakeNFT/Scenes /ShoppingCart/ShoppingCartViewModel.swift @@ -0,0 +1,12 @@ +// +// ShoppingCartViewModel.swift +// FakeNFT +// +// Created by Артем Кохан on 06.10.2023. +// + +import Foundation + +final class ShoppingCartViewModel { + +} diff --git a/FakeNFT/Scenes /Statistics/.DS_Store b/FakeNFT/Scenes /Statistics/.DS_Store new file mode 100644 index 0000000000..2b6891202a Binary files /dev/null and b/FakeNFT/Scenes /Statistics/.DS_Store differ diff --git a/FakeNFT/Scenes /Statistics/Extentions/EndPoint.swift b/FakeNFT/Scenes /Statistics/Extentions/EndPoint.swift new file mode 100644 index 0000000000..ee86b4361f --- /dev/null +++ b/FakeNFT/Scenes /Statistics/Extentions/EndPoint.swift @@ -0,0 +1,15 @@ +import Foundation + +enum Endpoint { + static func getUsers() -> URL { + URL(string: "https://64a03f83ed3c41bdd7a72309.mockapi.io/api/v1/users")! + } + + static func getProfile(id: String) -> URL { + URL(string: "https://64a03f83ed3c41bdd7a72309.mockapi.io/api/v1/users/\(id)")! + } + + static func getNFT(id: String) -> URL { + URL(string: "https://64a03f83ed3c41bdd7a72309.mockapi.io/api/v1/nft/\(id)")! + } +} diff --git a/FakeNFT/Scenes /Statistics/Extentions/GeometricParams.swift b/FakeNFT/Scenes /Statistics/Extentions/GeometricParams.swift new file mode 100644 index 0000000000..73d15bf997 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/Extentions/GeometricParams.swift @@ -0,0 +1,17 @@ +import UIKit + +struct GeometricParams { + let cellCount: Int + let leftInset: CGFloat + let rightInset: CGFloat + let cellSpacing: CGSize + let paddingWidth: CGFloat + + init(cellCount: Int, leftInset: CGFloat, rightInset: CGFloat, cellSpacing: CGSize) { + self.cellCount = cellCount + self.leftInset = leftInset + self.rightInset = rightInset + self.cellSpacing = cellSpacing + self.paddingWidth = leftInset + rightInset + CGFloat(cellCount - 1) * cellSpacing.width + } +} diff --git a/FakeNFT/Scenes /Statistics/Extentions/Observable.swift b/FakeNFT/Scenes /Statistics/Extentions/Observable.swift new file mode 100644 index 0000000000..787661edbb --- /dev/null +++ b/FakeNFT/Scenes /Statistics/Extentions/Observable.swift @@ -0,0 +1,31 @@ +import Foundation + +@propertyWrapper +final class Observable { + private var onChange: ((Value) -> Void)? + + var wrappedValue: Value { + didSet { + onChange?(wrappedValue) + } + } + + var projectedValue: Observable { + return self + } + + init(wrappedValue: Value) { + self.wrappedValue = wrappedValue + } + + func bind(executeInitially: Bool = true, action: @escaping (Value) -> Void) { + self.onChange = action + if executeInitially { + onChange?(wrappedValue) + } + } + + func unbind() { + onChange = nil + } +} diff --git a/FakeNFT/Scenes /Statistics/Extentions/UIView+Layout.swift b/FakeNFT/Scenes /Statistics/Extentions/UIView+Layout.swift new file mode 100644 index 0000000000..f36550f9f6 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/Extentions/UIView+Layout.swift @@ -0,0 +1,13 @@ +import UIKit + +final class VSpacer: UIView { + init(height: CGFloat) { + super.init(frame: .zero) + translatesAutoresizingMaskIntoConstraints = false + heightAnchor.constraint(equalToConstant: height).isActive = true + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserCollection/Model/StatisticsNFTModel.swift b/FakeNFT/Scenes /Statistics/StatUserCollection/Model/StatisticsNFTModel.swift new file mode 100644 index 0000000000..c293e3d500 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserCollection/Model/StatisticsNFTModel.swift @@ -0,0 +1,13 @@ +import Foundation + +struct StatisticsNFTModel: Decodable { + let createdAt: String + let name: String + let images: [URL] + let rating: Int + let description: String + let price: Double + let author: String + let id: String + +} diff --git a/FakeNFT/Scenes /Statistics/StatUserCollection/Model/StatisticsUserNFTCollectionModel.swift b/FakeNFT/Scenes /Statistics/StatUserCollection/Model/StatisticsUserNFTCollectionModel.swift new file mode 100644 index 0000000000..886b66ba72 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserCollection/Model/StatisticsUserNFTCollectionModel.swift @@ -0,0 +1,14 @@ +import Foundation + +struct StatisticsUserNFTCollectionModel { + private enum NetworkError: Error { + case someError + } + + let networkClient: NetworkClient + + func loadNFT(id: String, completion: @escaping (Result) -> Void) { + let request = DefaultNetworkRequest(endpoint: Endpoint.getNFT(id: id), dto: nil, httpMethod: .get) + networkClient.send(request: request, type: StatisticsNFTModel.self, onResponse: completion) + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserCollection/RatingStackView.swift b/FakeNFT/Scenes /Statistics/StatUserCollection/RatingStackView.swift new file mode 100644 index 0000000000..04016c6d1f --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserCollection/RatingStackView.swift @@ -0,0 +1,40 @@ +// +// RatingStackView.swift +// FakeNFT +// +// Created by Konstantin Zuykov on 02.11.2023. +// + +import UIKit + +final class RatingStackView: UIStackView { + + private let fillStarImage: UIImage? = UIImage(systemName: "star_yellow") + private let emptyStarImage: UIImage? = UIImage(systemName: "star") + + init(rating: Int = 5) { + super.init(frame: .zero) + axis = .horizontal + spacing = 2 + translatesAutoresizingMaskIntoConstraints = false + + (1...rating).forEach { + let imageView = UIImageView() + imageView.image = emptyStarImage + imageView.tag = $0 + addArrangedSubview(imageView) + } + } + + required init(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setupRating(rating: Int) { + subviews.forEach { + if let imageView = $0 as? UIImageView { + imageView.image = imageView.tag > rating ? emptyStarImage : fillStarImage + } + } + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserCollection/UIBlockingProgressHUD.swift b/FakeNFT/Scenes /Statistics/StatUserCollection/UIBlockingProgressHUD.swift new file mode 100644 index 0000000000..b7f25a047a --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserCollection/UIBlockingProgressHUD.swift @@ -0,0 +1,25 @@ +// +// UIBlockingProgressHUD.swift +// FakeNFT +// +// Created by Konstantin Zuykov on 02.11.2023. +// + +import UIKit +import ProgressHUD + +final class UIBlockingProgressHUD { + private static var window: UIWindow? { + return UIApplication.shared.windows.first + } + + static func show() { + window?.isUserInteractionEnabled = false + ProgressHUD.show() + } + + static func dismiss() { + window?.isUserInteractionEnabled = true + ProgressHUD.dismiss() + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionCellModel.swift b/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionCellModel.swift new file mode 100644 index 0000000000..dee9f7b5bf --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionCellModel.swift @@ -0,0 +1,26 @@ +import UIKit + +struct StatisticsUserNFTCollectionCellModel { + enum StarRating: Int { + case zero + case one + case two + case three + case four + case five + } + + let icon: URL? + let rating: StarRating + let name: String + let price: String +} + +extension StatisticsUserNFTCollectionCellModel { + init(nftModel: StatisticsNFTModel) { + icon = nftModel.images.first + rating = StarRating(rawValue: nftModel.rating) ?? .zero + name = nftModel.name + price = "\(nftModel.price) ETH" + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionViewCell.swift b/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionViewCell.swift new file mode 100644 index 0000000000..c8a1378333 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionViewCell.swift @@ -0,0 +1,140 @@ +import UIKit +import Kingfisher + +private enum Consts { + static let largeSpacing: CGFloat = 8 + static let smallSpacing: CGFloat = 4 + static let ratingHeight: CGFloat = 12 + static let nameHeight: CGFloat = 22 + static let priceHeight: CGFloat = 12 +} + +final class StatisticsUserNFTCollectionViewCell: UICollectionViewCell, ReuseIdentifying { + private let usersCollectionItemImage: UIImageView = { + let image = UIImageView() + image.layer.cornerRadius = 12 + image.layer.masksToBounds = true + image.heightAnchor.constraint(equalTo: image.widthAnchor).isActive = true + image.contentMode = .scaleAspectFit + return image + }() + + private let usersCollectionItemRating: UIImageView = { + let rating = UIImageView() + return rating + }() + + private let usersCollectionItemName: UILabel = { + let name = UILabel() + name.font = .bodyBold + return name + }() + + private let usersCollectionItemPrice: UILabel = { + let price = UILabel() + price.font = .systemFont(ofSize: 10, weight: .medium) + return price + }() + + private let usersCollectionItemCart: UIImageView = { + let cart = UIImageView() + cart.image = UIImage(named: "cart") + cart.heightAnchor.constraint(equalToConstant: 40).isActive = true + cart.widthAnchor.constraint(equalToConstant: 40).isActive = true + return cart + }() + + private let usersCollectionItemFavoriteButton: UIButton = { + let button = UIButton() + button.setImage(UIImage(named: "Like"), for: .normal) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + contentView.addSubview(usersCollectionItemImage) + usersCollectionItemImage.translatesAutoresizingMaskIntoConstraints = false + + usersCollectionItemImage.addSubview(usersCollectionItemFavoriteButton) + usersCollectionItemFavoriteButton.translatesAutoresizingMaskIntoConstraints = false + + contentView.addSubview(usersCollectionItemName) + usersCollectionItemName.translatesAutoresizingMaskIntoConstraints = false + + contentView.addSubview(usersCollectionItemRating) + usersCollectionItemRating.translatesAutoresizingMaskIntoConstraints = false + + contentView.addSubview(usersCollectionItemPrice) + usersCollectionItemPrice.translatesAutoresizingMaskIntoConstraints = false + + contentView.addSubview(usersCollectionItemCart) + usersCollectionItemCart.translatesAutoresizingMaskIntoConstraints = false + + let constraints = [ + usersCollectionItemImage.topAnchor.constraint(equalTo: contentView.topAnchor), + usersCollectionItemImage.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + usersCollectionItemImage.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + usersCollectionItemImage.widthAnchor.constraint(equalTo: contentView.widthAnchor), + + usersCollectionItemFavoriteButton.topAnchor.constraint(equalTo: usersCollectionItemImage.topAnchor, constant: 5), + usersCollectionItemFavoriteButton.trailingAnchor.constraint(equalTo: usersCollectionItemImage.trailingAnchor, constant: -5), + + usersCollectionItemRating.topAnchor.constraint(equalTo: usersCollectionItemImage.bottomAnchor, constant: 8), + usersCollectionItemRating.heightAnchor.constraint(equalToConstant: 12), + usersCollectionItemRating.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + + usersCollectionItemName.topAnchor.constraint(equalTo: usersCollectionItemRating.bottomAnchor, constant: 4), + usersCollectionItemName.heightAnchor.constraint(equalToConstant: 22), + usersCollectionItemName.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + usersCollectionItemName.trailingAnchor.constraint(lessThanOrEqualTo: usersCollectionItemCart.leadingAnchor, constant: -8), + + usersCollectionItemPrice.topAnchor.constraint(equalTo: usersCollectionItemName.bottomAnchor, constant: 4), + usersCollectionItemPrice.heightAnchor.constraint(equalToConstant: 12), + usersCollectionItemPrice.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + + usersCollectionItemCart.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + usersCollectionItemCart.topAnchor.constraint(equalTo: usersCollectionItemImage.bottomAnchor, constant: 24) + ] + + constraints.forEach { + $0.priority = .defaultHigh + } + + NSLayoutConstraint.activate(constraints) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func configure(with model: StatisticsUserNFTCollectionCellModel) { + usersCollectionItemImage.kf.setImage(with: model.icon) + setRating(rating: model.rating) + usersCollectionItemName.text = model.name + usersCollectionItemPrice.text = model.price + } + + private func setRating(rating: StatisticsUserNFTCollectionCellModel.StarRating) { + switch rating { + case .zero: + usersCollectionItemRating.image = UIImage(named: "propertyZero") + case .one: + usersCollectionItemRating.image = UIImage(named: "propertyOne") + case .two: + usersCollectionItemRating.image = UIImage(named: "propertyTwo") + case .three: + usersCollectionItemRating.image = UIImage(named: "propertyThree") + case .four: + usersCollectionItemRating.image = UIImage(named: "propertyFour") + case .five: + usersCollectionItemRating.image = UIImage(named: "propertyFive") + } + } +} + +extension StatisticsUserNFTCollectionViewCell { + static func heightForWidth(_ width: CGFloat) -> CGFloat { + return width + Consts.largeSpacing + 2 * Consts.smallSpacing + Consts.ratingHeight + Consts.nameHeight + Consts.priceHeight + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionViewController.swift b/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionViewController.swift new file mode 100644 index 0000000000..3e4db3ff6d --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserCollection/View/StatisticsUserNFTCollectionViewController.swift @@ -0,0 +1,123 @@ +import UIKit + +final class StatisticsUserNFTCollectionViewController: + UIViewController, + UICollectionViewDataSource, + UICollectionViewDelegateFlowLayout { + + let userCollection = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + + private let activityIndicator = UIActivityIndicatorView(style: .large) + + private let geometricParams = GeometricParams(cellCount: 3, leftInset: 16, rightInset: 16, cellSpacing: CGSize(width: 9, height: 28)) + + private let viewModel: StatisticsUserNFTCollectionViewModel + + init(viewModel: StatisticsUserNFTCollectionViewModel) { + self.viewModel = viewModel + super.init(nibName: nil, bundle: nil) + viewModel.$nfts.bind(executeInitially: true) { [weak self] _ in + self?.userCollection.reloadData() + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .background + userCollection.delegate = self + userCollection.dataSource = self + userCollection.register(StatisticsUserNFTCollectionViewCell.self) + + configureNavigationBar() + setupConstraints() + + viewModel.loadData() + } + + func setLoaderIsHidden(_ isHidden: Bool) { + if isHidden { + activityIndicator.stopAnimating() + } else { + activityIndicator.startAnimating() + } + } + + private func configureNavigationBar() { + let backImage = UIImage(systemName: "chevron.backward")? + .withTintColor(.ypBlack ?? .black) + .withRenderingMode(.alwaysOriginal) + navigationItem.title = "Коллекция NFT" + + if self !== navigationController?.viewControllers.first { + navigationItem.leftBarButtonItem = UIBarButtonItem( + image: backImage, + style: .plain, + target: self, + action: #selector(backTapped) + ) + } + } + + private func setupConstraints() { + view.addSubview(activityIndicator) + activityIndicator.layer.zPosition = 9999 + activityIndicator.translatesAutoresizingMaskIntoConstraints = false + + view.addSubview(userCollection) + userCollection.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + userCollection.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + userCollection.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), + userCollection.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + userCollection.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor), + activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } + + // MARK: - Actions + + @objc + private func backTapped() { + viewModel.didTapBack() + } +} + +// MARK: - UICollectionViewDataSource +extension StatisticsUserNFTCollectionViewController { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + viewModel.nfts.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell: StatisticsUserNFTCollectionViewCell = userCollection.dequeueReusableCell(indexPath: indexPath) + cell.configure(with: viewModel.nfts[indexPath.row]) + return cell + } +} + +// MARK: - UICollectionViewDelegateFlowLayout +extension StatisticsUserNFTCollectionViewController { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let availableWidth = collectionView.frame.width - geometricParams.paddingWidth + let cellWidth = floor(availableWidth / CGFloat(geometricParams.cellCount)) + let cellHeight = StatisticsUserNFTCollectionViewCell.heightForWidth(cellWidth) + return CGSize(width: cellWidth, height: cellHeight) + } + + func collectionView(_: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { + return UIEdgeInsets(top: 10, left: geometricParams.leftInset, bottom: 10, right: geometricParams.rightInset) + } + + func collectionView(_: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + return geometricParams.cellSpacing.height + } + + func collectionView(_: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + return geometricParams.cellSpacing.width + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserCollection/ViewModel/StatisticsUserNFTCollectionViewModel.swift b/FakeNFT/Scenes /Statistics/StatUserCollection/ViewModel/StatisticsUserNFTCollectionViewModel.swift new file mode 100644 index 0000000000..25409a73dd --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserCollection/ViewModel/StatisticsUserNFTCollectionViewModel.swift @@ -0,0 +1,57 @@ +import Foundation + +final class StatisticsUserNFTCollectionViewModel { + @Observable + var nfts: [StatisticsUserNFTCollectionCellModel] = [] + + @Observable + var isLoading: Bool = false + + private let model: StatisticsUserNFTCollectionModel + private let router: StatisticsNavigation + private let nftIDs: Set + + init(model: StatisticsUserNFTCollectionModel, router: StatisticsNavigation, nftIDs: [String]) { + self.model = model + self.router = router + self.nftIDs = Set(nftIDs) + + } + + func loadData() { + var nftIDsToLoad = nftIDs + var loadedDictionary: [String: StatisticsUserNFTCollectionCellModel] = [:] + + isLoading = true + + nftIDs.forEach { id in + model.loadNFT(id: id) { [weak self] result in + guard let self else { + return + } + + nftIDsToLoad.remove(id) + + switch result { + case .success(let nftModel): + loadedDictionary[id] = StatisticsUserNFTCollectionCellModel( + nftModel: nftModel + ) + case .failure(let error): + print(error) + } + + if nftIDsToLoad.isEmpty { + DispatchQueue.main.async { + self.isLoading = false + self.nfts = Array(loadedDictionary.values) + } + } + } + } + } + + func didTapBack() { + router.goBack() + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileModel.swift b/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileModel.swift new file mode 100644 index 0000000000..35af705945 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileModel.swift @@ -0,0 +1,20 @@ +import Foundation + +struct UserProfileModel: Decodable { + let name: String + let avatar: URL + let description: String + let website: URL + let nfts: [String] + let rating: String + let id: String +} + +struct StatisticsUserProfileModel { + let networkClient: NetworkClient + + func loadUser(id: String, completion: @escaping (Result) -> Void) { + let request = DefaultNetworkRequest(endpoint: Endpoint.getProfile(id: id), dto: nil, httpMethod: .get) + networkClient.send(request: request, type: UserProfileModel.self, onResponse: completion) + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileViewController.swift b/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileViewController.swift new file mode 100644 index 0000000000..e40e02c3f4 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileViewController.swift @@ -0,0 +1,180 @@ +import UIKit +import Kingfisher + +final class StatisticsUserProfileViewController: UIViewController { + private let usersAvatar: UIImageView = { + let usersAvatar = UIImageView() + usersAvatar.layer.cornerRadius = 35 + usersAvatar.layer.masksToBounds = true + usersAvatar.heightAnchor.constraint(equalToConstant: 70).isActive = true + usersAvatar.widthAnchor.constraint(equalToConstant: 70).isActive = true + return usersAvatar + }() + + private let userName: UILabel = { + let userName = UILabel() + userName.font = .headline3 + return userName + }() + + private let userDescription: UILabel = { + let userDescription = UILabel() + userDescription.font = .caption2 + userDescription.numberOfLines = 0 + return userDescription + }() + + private let usersWebsite: UIButton = { + let usersWebsite = UIButton() + usersWebsite.layer.cornerRadius = 16 + usersWebsite.layer.borderWidth = 1 + usersWebsite.setTitle("Перейти на сайт пользователя", for: .normal) + usersWebsite.layer.borderColor = UIColor.ypBlack?.cgColor + usersWebsite.titleLabel?.font = .caption1 + usersWebsite.setTitleColor(.ypBlack, for: .normal) + + return usersWebsite + }() + + private let usersCollectionButton: UIButton = { + let usersCollectionButton = UIButton() + usersCollectionButton.setTitleColor(.ypBlack, for: .normal) + usersCollectionButton.titleLabel?.font = .bodyBold + let chevron = UIImage(systemName: "chevron.forward")? + .withTintColor(.textPrimary) + .withRenderingMode(.alwaysOriginal) + let chevronImageView = UIImageView(image: chevron) + usersCollectionButton.addSubview(chevronImageView) + chevronImageView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + usersCollectionButton.titleLabel!.leadingAnchor.constraint(equalTo: usersCollectionButton.leadingAnchor), + chevronImageView.centerYAnchor.constraint(equalTo: usersCollectionButton.centerYAnchor), + chevronImageView.trailingAnchor.constraint(equalTo: usersCollectionButton.trailingAnchor) + ]) + return usersCollectionButton + }() + + private let activityIndicator = UIActivityIndicatorView(style: .large) + + private let viewModel: StatisticsUserProfileViewModel + + init(viewModel: StatisticsUserProfileViewModel) { + self.viewModel = viewModel + super.init(nibName: nil, bundle: nil) + + viewModel.$profile.bind(executeInitially: true) { [weak self] profile in + guard let self, let profile else { + return + } + + self.usersAvatar.kf.setImage(with: profile.avatar) + self.userName.text = profile.name + self.userDescription.text = profile.description + self.usersCollectionButton.setTitle("Коллекция NFT" + " (\(profile.nfts.count))", for: .normal) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + usersAvatar.kf.cancelDownloadTask() + } + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .background + + usersCollectionButton.addTarget(self, action: #selector(usersCollectionButtonTapped), for: .touchUpInside) + usersWebsite.addTarget(self, action: #selector(websiteButtonTapped), for: .touchUpInside) + + setupConstraints() + configureNavigationBar() + + viewModel.loadData() + } + + func setLoaderIsHidden(_ isHidden: Bool) { + isHidden ? activityIndicator.stopAnimating() : activityIndicator.startAnimating() + } + + private func setupConstraints() { + view.addSubview(activityIndicator) + activityIndicator.layer.zPosition = 9999 + activityIndicator.translatesAutoresizingMaskIntoConstraints = false + + let hStackAvatarAndName = UIStackView(arrangedSubviews: [usersAvatar, userName]) + hStackAvatarAndName.translatesAutoresizingMaskIntoConstraints = false + hStackAvatarAndName.axis = .horizontal + hStackAvatarAndName.spacing = 16 + + let vStack = UIStackView(arrangedSubviews: [ + hStackAvatarAndName, + VSpacer(height: 20), + userDescription, + VSpacer(height: 28), + usersWebsite, + VSpacer(height: 40), + usersCollectionButton + ]) + vStack.translatesAutoresizingMaskIntoConstraints = false + vStack.axis = .vertical + vStack.backgroundColor = .background + view.addSubview(vStack) + + let constraints = [ + vStack.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20), + vStack.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16), + vStack.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), + usersWebsite.heightAnchor.constraint(equalToConstant: 40), + usersAvatar.heightAnchor.constraint(equalToConstant: 70), + usersAvatar.widthAnchor.constraint(equalToConstant: 70), + activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor), + activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ] + + constraints.forEach { + $0.priority = .defaultHigh + } + + NSLayoutConstraint.activate(constraints) + } + + private func configureNavigationBar() { + let backImage = UIImage(systemName: "chevron.backward")? + .withTintColor(.ypBlack ?? .black) + .withRenderingMode(.alwaysOriginal) + + if self !== navigationController?.viewControllers.first { + navigationItem.leftBarButtonItem = UIBarButtonItem( + image: backImage, + style: .plain, + target: self, + action: #selector(backButtonTapped) + ) + } + } + + // MARK: - Actions + + @objc + private func usersCollectionButtonTapped() { + viewModel.didTapNFTsCollection() + } + + @objc + private func websiteButtonTapped() { + viewModel.didTapWebsite() + } + + @objc + private func backButtonTapped() { + viewModel.didTapBack() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + usersWebsite.layer.borderColor = UIColor.ypBlack?.cgColor + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileViewModel.swift b/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileViewModel.swift new file mode 100644 index 0000000000..86a45ed3fe --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserPage/StatisticsUserProfileViewModel.swift @@ -0,0 +1,58 @@ +import Foundation + +final class StatisticsUserProfileViewModel { + @Observable + var profile: UserProfileModel? + + @Observable + var isLoading: Bool = false + + private let id: String + private let router: StatisticsNavigation + private let model: StatisticsUserProfileModel + + init(id: String, router: StatisticsNavigation, model: StatisticsUserProfileModel) { + self.id = id + self.router = router + self.model = model + } + + func loadData() { + isLoading = true + model.loadUser(id: id) { result in + DispatchQueue.main.async { [weak self] in + guard let self else { + return + } + + self.isLoading = false + switch result { + case .success(let profile): + self.profile = profile + case .failure(let error): + print(error) + } + } + } + } + + func didTapBack() { + router.goBack() + } + + func didTapWebsite() { + guard let url = profile?.website else { + return + } + + router.goToUserWebsite(url: url) + } + + func didTapNFTsCollection() { + guard let profile else { + return + } + router.goToUserNFTCollection(nftIDs: profile.nfts) + //print(profile) + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/Model/ServerUserModel.swift b/FakeNFT/Scenes /Statistics/StatUserView/Model/ServerUserModel.swift new file mode 100644 index 0000000000..c25162023a --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/Model/ServerUserModel.swift @@ -0,0 +1,11 @@ +import Foundation + +struct ServerUserModel: Decodable { + let name: String + let avatar: URL + let description: String + let website: URL + let nfts: [String] + let rating: String + let id: String +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/Model/StatisticsLoader.swift b/FakeNFT/Scenes /Statistics/StatUserView/Model/StatisticsLoader.swift new file mode 100644 index 0000000000..e9dea0e876 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/Model/StatisticsLoader.swift @@ -0,0 +1,14 @@ +import Foundation + +class StatisticsLoader { + let networkClient: NetworkClient + + init(networkClient: NetworkClient) { + self.networkClient = networkClient + } + + func loadUsers(completion: @escaping (Result<[ServerUserModel], Error>) -> Void) { + let request = DefaultNetworkRequest(endpoint: Endpoint.getUsers(), dto: nil, httpMethod: .get) + networkClient.send(request: request, type: [ServerUserModel].self, onResponse: completion) + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/ProfileCellView.swift b/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/ProfileCellView.swift new file mode 100644 index 0000000000..48c5d64dce --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/ProfileCellView.swift @@ -0,0 +1,76 @@ +import UIKit + +class ProfileCellView: UIView { + var imageURL: URL? { + didSet { + guard let url = imageURL else { + return profilePhoto.kf.cancelDownloadTask() + } + + profilePhoto.kf.setImage(with: url) + } + } + + var text: String? { + didSet { + profileName.text = text + } + } + + var counter: Int? { + didSet { + profileNFTCount.text = counter.map { "\($0)" } ?? "" + } + } + + private let profilePhoto: UIImageView = { + let profilePhoto = UIImageView() + profilePhoto.layer.cornerRadius = 14 + profilePhoto.layer.masksToBounds = true + profilePhoto.image = UIImage(systemName: "person.crop.circle.fill")? + .withTintColor(.textSecondary) + .withRenderingMode(.alwaysOriginal) + return profilePhoto + }() + + private let profileName: UILabel = { + let profileName = UILabel() + profileName.font = .headline3 + profileName.textColor = .ypBlack + return profileName + }() + + private let profileNFTCount: UILabel = { + let profileNFTCount = UILabel() + profileNFTCount.font = .headline3 + return profileNFTCount + }() + + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = .ypLightGrey + layer.cornerRadius = 12 + + let hStack = UIStackView(arrangedSubviews: [profilePhoto, profileName]) + hStack.translatesAutoresizingMaskIntoConstraints = false + hStack.axis = .horizontal + hStack.spacing = 8 + addSubview(hStack) + + addSubview(profileNFTCount) + profileNFTCount.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + hStack.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16), + hStack.centerYAnchor.constraint(equalTo: centerYAnchor), + profileNFTCount.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16), + profileNFTCount.centerYAnchor.constraint(equalTo: centerYAnchor), + hStack.trailingAnchor.constraint(lessThanOrEqualTo: profileNFTCount.leadingAnchor), + profilePhoto.widthAnchor.constraint(equalToConstant: 28), + profilePhoto.heightAnchor.constraint(equalToConstant: 28) + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/StatisticsTableViewCell.swift b/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/StatisticsTableViewCell.swift new file mode 100644 index 0000000000..d78f6e18ad --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/StatisticsTableViewCell.swift @@ -0,0 +1,60 @@ +import UIKit +import Kingfisher + +final class StatisticsTableViewCell: UITableViewCell, ReuseIdentifying { + private var number: UILabel = { + var number = UILabel() + number.font = .caption1 + number.textColor = .textPrimary + return number + }() + + private let profileView = ProfileCellView() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + selectionStyle = .none + contentView.backgroundColor = .background + contentView.addSubview(number) + number.translatesAutoresizingMaskIntoConstraints = false + + profileView.translatesAutoresizingMaskIntoConstraints = false + + let hStack = UIStackView(arrangedSubviews: [number, profileView]) + hStack.translatesAutoresizingMaskIntoConstraints = false + hStack.axis = .horizontal + hStack.spacing = 12 + contentView.addSubview(hStack) + + let constraints = [ + hStack.topAnchor.constraint(equalTo: topAnchor), + hStack.trailingAnchor.constraint(equalTo: trailingAnchor), + hStack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8), + hStack.leadingAnchor.constraint(equalTo: leadingAnchor), + contentView.heightAnchor.constraint(equalToConstant: 88), + profileView.heightAnchor.constraint(equalToConstant: 80) + ] + + constraints.forEach { + $0.priority = .defaultHigh + } + + NSLayoutConstraint.activate(constraints) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prepareForReuse() { + profileView.imageURL = nil + } + + func configureWith(model: StatisticsTableViewCellModel) { + number.text = model.number.description + profileView.imageURL = model.profilePhoto + profileView.text = model.profileName + profileView.counter = model.profileNFTCount + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/StatisticsTableViewCellModel.swift b/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/StatisticsTableViewCellModel.swift new file mode 100644 index 0000000000..f30218b269 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/StatisticsTableView/StatisticsTableViewCellModel.swift @@ -0,0 +1,17 @@ +import Foundation + +struct StatisticsTableViewCellModel { + let number: String + let profilePhoto: URL + let profileName: String + let profileNFTCount: Int +} + +extension StatisticsTableViewCellModel { + init(userModel: UserModel) { + number = String(userModel.rating) + profilePhoto = userModel.avatar + profileName = userModel.name + profileNFTCount = userModel.nfts.count + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/StatisticsViewController.swift b/FakeNFT/Scenes /Statistics/StatUserView/StatisticsViewController.swift new file mode 100644 index 0000000000..1ccde54ba1 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/StatisticsViewController.swift @@ -0,0 +1,133 @@ +import UIKit + +final class StatisticsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { + + private let sortButton: UIButton = { + let sortButton = UIButton() + sortButton.setImage(UIImage(named: "sortButton"), for: .normal) + return sortButton + }() + + private let tableView = UITableView(frame: .zero) + private let activityIndicator = UIActivityIndicatorView(style: .large) + private let viewModel: StatisticsViewModel + + init(viewModel: StatisticsViewModel) { + self.viewModel = viewModel + super.init(nibName: nil, bundle: nil) + viewModel.$userModels.bind(executeInitially: true) { [weak self] _ in + self?.tableView.reloadData() + } + viewModel.$isLoading.bind(executeInitially: true) { [weak self] isLoading in + self?.setLoaderIsHidden(!isLoading) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .background + tableView.register(StatisticsTableViewCell.self) + tableView.delegate = self + tableView.dataSource = self + sortButton.addTarget(self, action: #selector(statisticsFilter), for: .touchUpInside) + + setupConstraints() + navigationItem.rightBarButtonItem = UIBarButtonItem(customView: sortButton) + + viewModel.loadData() + } + + // MARK: - StatisticsView + + func setLoaderIsHidden(_ isHidden: Bool) { + isHidden ? activityIndicator.stopAnimating() : activityIndicator.startAnimating() + } + + private func setupConstraints() { + view.addSubview(activityIndicator) + activityIndicator.layer.zPosition = 9999 + activityIndicator.translatesAutoresizingMaskIntoConstraints = false + + sortButton.translatesAutoresizingMaskIntoConstraints = false + + view.addSubview(tableView) + tableView.separatorStyle = .none + tableView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + sortButton.heightAnchor.constraint(equalToConstant: 42), + sortButton.widthAnchor.constraint(equalToConstant: 42), + + tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16), + tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16), + + activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor), + activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } + + @objc + private func statisticsFilter() { + let alert = UIAlertController( + title: nil, + message: "Сортировка", + preferredStyle: .actionSheet + ) + + let nameAction = UIAlertAction( + title: "По имени", + style: .default + ) { [weak self] _ in + self?.viewModel.didSelectSort(.name) + alert.dismiss(animated: true) + } + + let ratingAction = UIAlertAction( + title: "По рейтингу", + style: .default + ) { [weak self] _ in + self?.viewModel.didSelectSort(.rating) + alert.dismiss(animated: true) + } + + let closeAction = UIAlertAction( + title: "Закрыть", + style: .cancel) { _ in + alert.dismiss(animated: true) + } + + [nameAction, ratingAction, closeAction].forEach { + alert.addAction($0) + } + + present(alert, animated: true) + } +} + +// MARK: - UITableViewDataSource +extension StatisticsViewController { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + viewModel.userModels.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell: StatisticsTableViewCell = tableView.dequeueReusableCell() + let model = StatisticsTableViewCellModel( + userModel: viewModel.userModels[indexPath.row] + ) + cell.configureWith(model: model) + return cell + } +} + +extension StatisticsViewController { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + viewModel.didSelectItem(indexPath: indexPath) + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/UserViewCellViewModel.swift b/FakeNFT/Scenes /Statistics/StatUserView/UserViewCellViewModel.swift new file mode 100644 index 0000000000..5e74ce20c6 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/UserViewCellViewModel.swift @@ -0,0 +1,34 @@ +// +// UserViewCellViewModel.swift +// FakeNFT +// +// Created by Konstantin Zuykov on 02.11.2023. +// + +import Foundation + +final class UserViewCellViewModel { + private let user: User + private let cellIndex: Int + + var index: String { + return String(cellIndex + 1) + } + + var name: String { + return user.name + } + + var count: String { + return String(user.nfts.count) + } + + var avatarURL: URL? { + return URL(string: user.avatar) + } + + init(user: User, cellIndex: Int) { + self.user = user + self.cellIndex = cellIndex + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/ViewModel/StatisticsViewModel.swift b/FakeNFT/Scenes /Statistics/StatUserView/ViewModel/StatisticsViewModel.swift new file mode 100644 index 0000000000..9d357afe52 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/ViewModel/StatisticsViewModel.swift @@ -0,0 +1,66 @@ +import UIKit + +final class StatisticsViewModel { + enum SortType { + case name + case rating + } + + @Observable + var userModels: [UserModel] = [] + + @Observable + var isLoading: Bool = false + + private let model: StatisticsLoader + private let router: StatisticsNavigation + private var sorting: SortType = .rating { + didSet { + userModels = applySort(sorting, to: userModels) + } + } + + init(model: StatisticsLoader, router: StatisticsNavigation) { + self.model = model + self.router = router + } + + func loadData() { + isLoading = true + model.loadUsers { result in + DispatchQueue.main.async { [weak self] in + guard let self else { + return + } + self.isLoading = false + + switch result { + case let .success(models): + let viewModelModels = models.map(UserModel.init(serverModel:)) + self.userModels = self.applySort(self.sorting, to: viewModelModels) + case let .failure(error): + print(error) + } + } + } + } + + func didSelectItem(indexPath: IndexPath) { + router.goToProfile(userID: userModels[indexPath.row].id) + } + + func didSelectSort(_ sort: SortType) { + sorting = sort + } + + private func applySort(_ sort: SortType, to models: [UserModel]) -> [UserModel] { + models.sorted { first, second in + switch sort { + case .name: + return first.name < second.name + case .rating: + return first.rating < second.rating + } + } + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/ViewModel/UserModel.swift b/FakeNFT/Scenes /Statistics/StatUserView/ViewModel/UserModel.swift new file mode 100644 index 0000000000..41baec27bb --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/ViewModel/UserModel.swift @@ -0,0 +1,23 @@ +import Foundation + +struct UserModel { + let name: String + let avatar: URL + let description: String + let website: URL + let nfts: [String] + let rating: Int + let id: String +} + +extension UserModel { + init(serverModel: ServerUserModel) { + name = serverModel.name + avatar = serverModel.avatar + description = serverModel.description + website = serverModel.website + nfts = serverModel.nfts + rating = Int(serverModel.rating) ?? 0 + id = serverModel.id + } +} diff --git a/FakeNFT/Scenes /Statistics/StatUserView/WebKit/WebKit.swift b/FakeNFT/Scenes /Statistics/StatUserView/WebKit/WebKit.swift new file mode 100644 index 0000000000..f34e9d2d39 --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatUserView/WebKit/WebKit.swift @@ -0,0 +1,28 @@ +import UIKit +import WebKit + +class WebViewController: UIViewController { + private let url: URL + + init(url: URL) { + self.url = url + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + let webView = WKWebView(frame: view.bounds) + view.addSubview(webView) + webView.load(URLRequest(url: url)) + let dismissButton = UIBarButtonItem(title: "Dismiss", style: .plain, target: self, action: #selector(dismissButtonTapped)) + navigationItem.rightBarButtonItem = dismissButton + } + + @objc private func dismissButtonTapped() { + navigationController?.dismiss(animated: true, completion: nil) + } +} diff --git a/FakeNFT/Scenes /Statistics/StatisticsRouter.swift b/FakeNFT/Scenes /Statistics/StatisticsRouter.swift new file mode 100644 index 0000000000..d9bf06834f --- /dev/null +++ b/FakeNFT/Scenes /Statistics/StatisticsRouter.swift @@ -0,0 +1,68 @@ +import UIKit +import WebKit + +protocol StatisticsNavigationProtocol { + func goBack() + func goToProfile(userID: String) + func goToUserWebsite(url: URL) + func goToUserNFTCollection(nftIDs: [String]) +} + +final class StatisticsNavigation: StatisticsNavigationProtocol { + weak var navigationController: UINavigationController? + + private let networkClient = DefaultNetworkClient() + + func goBack() { + navigationController?.popViewController(animated: true) + } + + func goToProfile(userID: String) { + let profileViewController = assembleUserCardModule(userID: userID) + navigationController?.pushViewController(profileViewController, animated: true) + } + + func goToUserWebsite(url: URL) { + let webKitViewController = assembleWKWebView(url: url) + navigationController?.pushViewController(webKitViewController, animated: true) + } + + func goToUserNFTCollection(nftIDs: [String]) { + let collectionViewController = assembleUserCollectionModule(nftIDs: nftIDs) + navigationController?.pushViewController(collectionViewController, animated: true) + } +} + +extension StatisticsNavigation { + func assembleStatisticsModule() -> UIViewController { + let model = StatisticsLoader(networkClient: networkClient) + let viewModel = StatisticsViewModel(model: model, router: self) + let view = StatisticsViewController(viewModel: viewModel) + + return view + } + + private func assembleUserCardModule(userID: String) -> UIViewController { + let model = StatisticsUserProfileModel(networkClient: networkClient) + let viewModel = StatisticsUserProfileViewModel(id: userID, router: self, model: model) + let view = StatisticsUserProfileViewController(viewModel: viewModel) + + return view + } + + private func assembleUserCollectionModule(nftIDs: [String]) -> UIViewController { + let model = StatisticsUserNFTCollectionModel(networkClient: networkClient) + let viewModel = StatisticsUserNFTCollectionViewModel( + model: model, + router: self, + nftIDs: nftIDs + ) + let view = StatisticsUserNFTCollectionViewController(viewModel: viewModel) + + return view + } + + private func assembleWKWebView(url: URL) -> UIViewController { + WebViewController(url: url) + } +} diff --git a/FakeNFT/TabBarController.swift b/FakeNFT/TabBarController.swift new file mode 100644 index 0000000000..626fe3c4ba --- /dev/null +++ b/FakeNFT/TabBarController.swift @@ -0,0 +1,65 @@ +// +// TabBarController.swift +// FakeNFT +// +// Created by Артем Кохан on 06.10.2023. +// + +import UIKit + +final class TabBarController: UITabBarController { + + override func viewDidLoad() { + super.viewDidLoad() + + // Профиль + let profileViewController = ProfileViewController() + + let profileViewModel = ProfileViewModel() + profileViewController.profileViewModel = profileViewModel + + profileViewController.tabBarItem = UITabBarItem( + title: "Профиль", + image: UIImage(systemName: "circle.fill"), + selectedImage: nil) + + // Каталог + let catalogViewController = CatalogViewController() + + let catalogViewModel = CatalogViewModel() + catalogViewController.catalogViewModel = catalogViewModel + + catalogViewController.tabBarItem = UITabBarItem( + title: "Каталог", + image: UIImage(systemName: "square.stack.3d.up.fill"), + selectedImage: nil) + + // Корзина + let shoppingCartViewController = ShoppingCartViewController() + + let shoppingCartViewModel = ShoppingCartViewModel() + shoppingCartViewController.shoppingCartViewModel = shoppingCartViewModel + + shoppingCartViewController.tabBarItem = UITabBarItem( + title: "Корзина", + image: UIImage(systemName: "trash"), + selectedImage: nil) + + // Статистика + let statisticsNavigation = StatisticsNavigation() + let statisticsVC = statisticsNavigation.assembleStatisticsModule() + let statisticsViewController = UINavigationController(rootViewController: statisticsVC) + statisticsNavigation.navigationController = statisticsViewController + + statisticsViewController.tabBarItem = UITabBarItem( + title: "Статистика", + image: UIImage(named: "statisticsTabBarImageNoActive"), + selectedImage: UIImage(named: "statisticsTabBarImageActive")) + + self.viewControllers = [ + profileViewController, + catalogViewController, + shoppingCartViewController, + statisticsViewController] + } +}