From 57a1d74f52f3f90b771d43d1588e3484ead8ea1a Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Wed, 28 Feb 2024 16:47:51 +0300 Subject: [PATCH 01/13] notepad module logic setup --- Everyday.xcodeproj/project.pbxproj | 317 +++++++++++++++++- Everyday/Entities/User.swift | 30 ++ Everyday/Entities/Workout.swift | 68 ++++ Everyday/Extensions/UIColor+Extension.swift | 20 +- Everyday/Extensions/UIView+Extension.swift | 1 - Everyday/Helpers/CustomError.swift | 12 + .../ExerciseScene/ExerciseContainer.swift | 43 +++ .../ExerciseScene/ExerciseInteractor.swift | 16 + .../ExerciseScene/ExercisePresenter.swift | 51 +++ .../ExerciseScene/ExerciseProtocols.swift | 38 +++ .../ExerciseScene/ExerciseRouter.swift | 26 ++ .../ExerciseViewController.swift | 128 +++++++ .../Models/ExerciseViewModel.swift | 33 ++ .../Notepad/ExtraScene/ExtraContainer.swift | 39 +++ .../Notepad/ExtraScene/ExtraInteractor.swift | 16 + .../Notepad/ExtraScene/ExtraPresenter.swift | 31 ++ .../Notepad/ExtraScene/ExtraProtocols.swift | 31 ++ .../Notepad/ExtraScene/ExtraRouter.swift | 15 + .../ExtraScene/ExtraViewController.swift | 51 +++ .../ExtraScene/Models/ExtraViewModel.swift | 8 + .../Modules/Notepad/NotepadInteractor.swift | 16 - .../Modules/Notepad/NotepadPresenter.swift | 31 -- .../Modules/Notepad/NotepadProtocols.swift | 31 -- Everyday/Modules/Notepad/NotepadRouter.swift | 15 - .../Models/NotepadViewModel.swift | 27 ++ .../{ => NotepadScene}/NotepadContainer.swift | 2 + .../NotepadScene/NotepadInteractor.swift | 51 +++ .../NotepadScene/NotepadPresenter.swift | 88 +++++ .../NotepadScene/NotepadProtocols.swift | 47 +++ .../Notepad/NotepadScene/NotepadRouter.swift | 27 ++ .../NotepadSectionHeaderView.swift | 122 +++++++ .../NotepadScene/NotepadTableViewCell.swift | 70 ++++ .../NotepadScene/NotepadViewController.swift | 188 +++++++++++ .../Notepad/NotepadViewController.swift | 32 -- .../Models/ResultsViewModel.swift | 35 ++ .../ResultsScene/ResultsContainer.swift | 42 +++ .../ResultsScene/ResultsInteractor.swift | 16 + .../ResultsScene/ResultsPresenter.swift | 60 ++++ .../ResultsScene/ResultsProtocols.swift | 43 +++ .../Notepad/ResultsScene/ResultsRouter.swift | 33 ++ .../ResultsScene/ResultsTableViewCell.swift | 131 ++++++++ .../ResultsScene/ResultsViewController.swift | 229 +++++++++++++ .../TimerScene/Models/TimerViewModel.swift | 43 +++ .../Notepad/TimerScene/TimerContainer.swift | 41 +++ .../Notepad/TimerScene/TimerInteractor.swift | 16 + .../Notepad/TimerScene/TimerPresenter.swift | 72 ++++ .../Notepad/TimerScene/TimerProtocols.swift | 39 +++ .../Notepad/TimerScene/TimerRouter.swift | 23 ++ .../TimerScene/TimerViewController.swift | 166 +++++++++ .../Models/TrainingViewModel.swift | 27 ++ .../TrainingScene/TrainingContainer.swift | 42 +++ .../TrainingScene/TrainingInteractor.swift | 16 + .../TrainingScene/TrainingPresenter.swift | 111 ++++++ .../TrainingScene/TrainingProtocols.swift | 46 +++ .../TrainingScene/TrainingRouter.swift | 50 +++ .../TrainingScene/TrainingTableViewCell.swift | 158 +++++++++ .../TrainingViewController.swift | 175 ++++++++++ Everyday/Services/Day/DayService.swift | 36 ++ 58 files changed, 3229 insertions(+), 142 deletions(-) create mode 100644 Everyday/Entities/User.swift create mode 100644 Everyday/Entities/Workout.swift create mode 100644 Everyday/Helpers/CustomError.swift create mode 100644 Everyday/Modules/Notepad/ExerciseScene/ExerciseContainer.swift create mode 100644 Everyday/Modules/Notepad/ExerciseScene/ExerciseInteractor.swift create mode 100644 Everyday/Modules/Notepad/ExerciseScene/ExercisePresenter.swift create mode 100644 Everyday/Modules/Notepad/ExerciseScene/ExerciseProtocols.swift create mode 100644 Everyday/Modules/Notepad/ExerciseScene/ExerciseRouter.swift create mode 100644 Everyday/Modules/Notepad/ExerciseScene/ExerciseViewController.swift create mode 100644 Everyday/Modules/Notepad/ExerciseScene/Models/ExerciseViewModel.swift create mode 100644 Everyday/Modules/Notepad/ExtraScene/ExtraContainer.swift create mode 100644 Everyday/Modules/Notepad/ExtraScene/ExtraInteractor.swift create mode 100644 Everyday/Modules/Notepad/ExtraScene/ExtraPresenter.swift create mode 100644 Everyday/Modules/Notepad/ExtraScene/ExtraProtocols.swift create mode 100644 Everyday/Modules/Notepad/ExtraScene/ExtraRouter.swift create mode 100644 Everyday/Modules/Notepad/ExtraScene/ExtraViewController.swift create mode 100644 Everyday/Modules/Notepad/ExtraScene/Models/ExtraViewModel.swift delete mode 100644 Everyday/Modules/Notepad/NotepadInteractor.swift delete mode 100644 Everyday/Modules/Notepad/NotepadPresenter.swift delete mode 100644 Everyday/Modules/Notepad/NotepadProtocols.swift delete mode 100644 Everyday/Modules/Notepad/NotepadRouter.swift create mode 100644 Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift rename Everyday/Modules/Notepad/{ => NotepadScene}/NotepadContainer.swift (95%) create mode 100644 Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift create mode 100644 Everyday/Modules/Notepad/NotepadScene/NotepadPresenter.swift create mode 100644 Everyday/Modules/Notepad/NotepadScene/NotepadProtocols.swift create mode 100644 Everyday/Modules/Notepad/NotepadScene/NotepadRouter.swift create mode 100644 Everyday/Modules/Notepad/NotepadScene/NotepadSectionHeaderView.swift create mode 100644 Everyday/Modules/Notepad/NotepadScene/NotepadTableViewCell.swift create mode 100644 Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift delete mode 100644 Everyday/Modules/Notepad/NotepadViewController.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/ResultsContainer.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/ResultsInteractor.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/ResultsPresenter.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/ResultsProtocols.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/ResultsRouter.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift create mode 100644 Everyday/Modules/Notepad/TimerScene/Models/TimerViewModel.swift create mode 100644 Everyday/Modules/Notepad/TimerScene/TimerContainer.swift create mode 100644 Everyday/Modules/Notepad/TimerScene/TimerInteractor.swift create mode 100644 Everyday/Modules/Notepad/TimerScene/TimerPresenter.swift create mode 100644 Everyday/Modules/Notepad/TimerScene/TimerProtocols.swift create mode 100644 Everyday/Modules/Notepad/TimerScene/TimerRouter.swift create mode 100644 Everyday/Modules/Notepad/TimerScene/TimerViewController.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/Models/TrainingViewModel.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/TrainingContainer.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/TrainingInteractor.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/TrainingProtocols.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift create mode 100644 Everyday/Services/Day/DayService.swift diff --git a/Everyday.xcodeproj/project.pbxproj b/Everyday.xcodeproj/project.pbxproj index 2c635c6..4a72299 100644 --- a/Everyday.xcodeproj/project.pbxproj +++ b/Everyday.xcodeproj/project.pbxproj @@ -114,6 +114,50 @@ 9EE8AE392B7FB96E001D126F /* WorkoutProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE8AE332B7FB96E001D126F /* WorkoutProtocols.swift */; }; 9EE8AE3A2B7FB96E001D126F /* WorkoutInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE8AE342B7FB96E001D126F /* WorkoutInteractor.swift */; }; 9EE8AE3B2B7FB96E001D126F /* WorkoutContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE8AE352B7FB96E001D126F /* WorkoutContainer.swift */; }; + CEED457A2B8F693E00DD4058 /* CustomError.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45792B8F693E00DD4058 /* CustomError.swift */; }; + CEED457D2B8F69C500DD4058 /* DayService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED457C2B8F69C500DD4058 /* DayService.swift */; }; + CEED45802B8F6A7B00DD4058 /* Workout.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED457F2B8F6A7B00DD4058 /* Workout.swift */; }; + CEED45822B8F6A8F00DD4058 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45812B8F6A8F00DD4058 /* User.swift */; }; + CEED45862B8F6B6C00DD4058 /* NotepadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45852B8F6B6C00DD4058 /* NotepadViewModel.swift */; }; + CEED45882B8F6D4400DD4058 /* NotepadSectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45872B8F6D4400DD4058 /* NotepadSectionHeaderView.swift */; }; + CEED458A2B8F6D7500DD4058 /* NotepadTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45892B8F6D7500DD4058 /* NotepadTableViewCell.swift */; }; + CEED45922B8F6DCE00DD4058 /* TrainingPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED458C2B8F6DCE00DD4058 /* TrainingPresenter.swift */; }; + CEED45932B8F6DCE00DD4058 /* TrainingRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED458D2B8F6DCE00DD4058 /* TrainingRouter.swift */; }; + CEED45942B8F6DCE00DD4058 /* TrainingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED458E2B8F6DCE00DD4058 /* TrainingViewController.swift */; }; + CEED45952B8F6DCE00DD4058 /* TrainingProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED458F2B8F6DCE00DD4058 /* TrainingProtocols.swift */; }; + CEED45962B8F6DCE00DD4058 /* TrainingInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45902B8F6DCE00DD4058 /* TrainingInteractor.swift */; }; + CEED45972B8F6DCE00DD4058 /* TrainingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45912B8F6DCE00DD4058 /* TrainingContainer.swift */; }; + CEED459A2B8F6DE200DD4058 /* TrainingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45992B8F6DE200DD4058 /* TrainingViewModel.swift */; }; + CEED459C2B8F6E2700DD4058 /* TrainingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED459B2B8F6E2700DD4058 /* TrainingTableViewCell.swift */; }; + CEED45A52B8F6EF500DD4058 /* ExercisePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED459F2B8F6EF500DD4058 /* ExercisePresenter.swift */; }; + CEED45A62B8F6EF500DD4058 /* ExerciseRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45A02B8F6EF500DD4058 /* ExerciseRouter.swift */; }; + CEED45A72B8F6EF500DD4058 /* ExerciseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45A12B8F6EF500DD4058 /* ExerciseViewController.swift */; }; + CEED45A82B8F6EF500DD4058 /* ExerciseProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45A22B8F6EF500DD4058 /* ExerciseProtocols.swift */; }; + CEED45A92B8F6EF500DD4058 /* ExerciseInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45A32B8F6EF500DD4058 /* ExerciseInteractor.swift */; }; + CEED45AA2B8F6EF500DD4058 /* ExerciseContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45A42B8F6EF500DD4058 /* ExerciseContainer.swift */; }; + CEED45AD2B8F6F0500DD4058 /* ExerciseViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45AC2B8F6F0500DD4058 /* ExerciseViewModel.swift */; }; + CEED45B52B8F6F9300DD4058 /* ResultsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45AF2B8F6F9300DD4058 /* ResultsPresenter.swift */; }; + CEED45B62B8F6F9300DD4058 /* ResultsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45B02B8F6F9300DD4058 /* ResultsRouter.swift */; }; + CEED45B72B8F6F9300DD4058 /* ResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45B12B8F6F9300DD4058 /* ResultsViewController.swift */; }; + CEED45B82B8F6F9300DD4058 /* ResultsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45B22B8F6F9300DD4058 /* ResultsProtocols.swift */; }; + CEED45B92B8F6F9300DD4058 /* ResultsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45B32B8F6F9300DD4058 /* ResultsInteractor.swift */; }; + CEED45BA2B8F6F9300DD4058 /* ResultsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45B42B8F6F9300DD4058 /* ResultsContainer.swift */; }; + CEED45BD2B8F6FA300DD4058 /* ResultsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45BC2B8F6FA300DD4058 /* ResultsViewModel.swift */; }; + CEED45BF2B8F6FDB00DD4058 /* ResultsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45BE2B8F6FDB00DD4058 /* ResultsTableViewCell.swift */; }; + CEED45C72B8F701800DD4058 /* TimerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45C12B8F701800DD4058 /* TimerPresenter.swift */; }; + CEED45C82B8F701800DD4058 /* TimerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45C22B8F701800DD4058 /* TimerRouter.swift */; }; + CEED45C92B8F701800DD4058 /* TimerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45C32B8F701800DD4058 /* TimerViewController.swift */; }; + CEED45CA2B8F701800DD4058 /* TimerProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45C42B8F701800DD4058 /* TimerProtocols.swift */; }; + CEED45CB2B8F701800DD4058 /* TimerInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45C52B8F701800DD4058 /* TimerInteractor.swift */; }; + CEED45CC2B8F701800DD4058 /* TimerContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45C62B8F701800DD4058 /* TimerContainer.swift */; }; + CEED45CF2B8F702800DD4058 /* TimerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45CE2B8F702800DD4058 /* TimerViewModel.swift */; }; + CEED45D72B8F708100DD4058 /* ExtraPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45D12B8F708100DD4058 /* ExtraPresenter.swift */; }; + CEED45D82B8F708100DD4058 /* ExtraRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45D22B8F708100DD4058 /* ExtraRouter.swift */; }; + CEED45D92B8F708100DD4058 /* ExtraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45D32B8F708100DD4058 /* ExtraViewController.swift */; }; + CEED45DA2B8F708100DD4058 /* ExtraProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45D42B8F708100DD4058 /* ExtraProtocols.swift */; }; + CEED45DB2B8F708100DD4058 /* ExtraInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45D52B8F708100DD4058 /* ExtraInteractor.swift */; }; + CEED45DC2B8F708100DD4058 /* ExtraContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45D62B8F708100DD4058 /* ExtraContainer.swift */; }; + CEED45DF2B8F70BB00DD4058 /* ExtraViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45DE2B8F70BB00DD4058 /* ExtraViewModel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -215,6 +259,50 @@ 9EE8AE332B7FB96E001D126F /* WorkoutProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutProtocols.swift; sourceTree = ""; }; 9EE8AE342B7FB96E001D126F /* WorkoutInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutInteractor.swift; sourceTree = ""; }; 9EE8AE352B7FB96E001D126F /* WorkoutContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutContainer.swift; sourceTree = ""; }; + CEED45792B8F693E00DD4058 /* CustomError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomError.swift; sourceTree = ""; }; + CEED457C2B8F69C500DD4058 /* DayService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayService.swift; sourceTree = ""; }; + CEED457F2B8F6A7B00DD4058 /* Workout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Workout.swift; sourceTree = ""; }; + CEED45812B8F6A8F00DD4058 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + CEED45852B8F6B6C00DD4058 /* NotepadViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotepadViewModel.swift; sourceTree = ""; }; + CEED45872B8F6D4400DD4058 /* NotepadSectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotepadSectionHeaderView.swift; sourceTree = ""; }; + CEED45892B8F6D7500DD4058 /* NotepadTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotepadTableViewCell.swift; sourceTree = ""; }; + CEED458C2B8F6DCE00DD4058 /* TrainingPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingPresenter.swift; sourceTree = ""; }; + CEED458D2B8F6DCE00DD4058 /* TrainingRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingRouter.swift; sourceTree = ""; }; + CEED458E2B8F6DCE00DD4058 /* TrainingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingViewController.swift; sourceTree = ""; }; + CEED458F2B8F6DCE00DD4058 /* TrainingProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingProtocols.swift; sourceTree = ""; }; + CEED45902B8F6DCE00DD4058 /* TrainingInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingInteractor.swift; sourceTree = ""; }; + CEED45912B8F6DCE00DD4058 /* TrainingContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingContainer.swift; sourceTree = ""; }; + CEED45992B8F6DE200DD4058 /* TrainingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingViewModel.swift; sourceTree = ""; }; + CEED459B2B8F6E2700DD4058 /* TrainingTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingTableViewCell.swift; sourceTree = ""; }; + CEED459F2B8F6EF500DD4058 /* ExercisePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExercisePresenter.swift; sourceTree = ""; }; + CEED45A02B8F6EF500DD4058 /* ExerciseRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseRouter.swift; sourceTree = ""; }; + CEED45A12B8F6EF500DD4058 /* ExerciseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseViewController.swift; sourceTree = ""; }; + CEED45A22B8F6EF500DD4058 /* ExerciseProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseProtocols.swift; sourceTree = ""; }; + CEED45A32B8F6EF500DD4058 /* ExerciseInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseInteractor.swift; sourceTree = ""; }; + CEED45A42B8F6EF500DD4058 /* ExerciseContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseContainer.swift; sourceTree = ""; }; + CEED45AC2B8F6F0500DD4058 /* ExerciseViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExerciseViewModel.swift; sourceTree = ""; }; + CEED45AF2B8F6F9300DD4058 /* ResultsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsPresenter.swift; sourceTree = ""; }; + CEED45B02B8F6F9300DD4058 /* ResultsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsRouter.swift; sourceTree = ""; }; + CEED45B12B8F6F9300DD4058 /* ResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsViewController.swift; sourceTree = ""; }; + CEED45B22B8F6F9300DD4058 /* ResultsProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsProtocols.swift; sourceTree = ""; }; + CEED45B32B8F6F9300DD4058 /* ResultsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsInteractor.swift; sourceTree = ""; }; + CEED45B42B8F6F9300DD4058 /* ResultsContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsContainer.swift; sourceTree = ""; }; + CEED45BC2B8F6FA300DD4058 /* ResultsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsViewModel.swift; sourceTree = ""; }; + CEED45BE2B8F6FDB00DD4058 /* ResultsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsTableViewCell.swift; sourceTree = ""; }; + CEED45C12B8F701800DD4058 /* TimerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerPresenter.swift; sourceTree = ""; }; + CEED45C22B8F701800DD4058 /* TimerRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerRouter.swift; sourceTree = ""; }; + CEED45C32B8F701800DD4058 /* TimerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerViewController.swift; sourceTree = ""; }; + CEED45C42B8F701800DD4058 /* TimerProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerProtocols.swift; sourceTree = ""; }; + CEED45C52B8F701800DD4058 /* TimerInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerInteractor.swift; sourceTree = ""; }; + CEED45C62B8F701800DD4058 /* TimerContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerContainer.swift; sourceTree = ""; }; + CEED45CE2B8F702800DD4058 /* TimerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerViewModel.swift; sourceTree = ""; }; + CEED45D12B8F708100DD4058 /* ExtraPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraPresenter.swift; sourceTree = ""; }; + CEED45D22B8F708100DD4058 /* ExtraRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraRouter.swift; sourceTree = ""; }; + CEED45D32B8F708100DD4058 /* ExtraViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraViewController.swift; sourceTree = ""; }; + CEED45D42B8F708100DD4058 /* ExtraProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraProtocols.swift; sourceTree = ""; }; + CEED45D52B8F708100DD4058 /* ExtraInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraInteractor.swift; sourceTree = ""; }; + CEED45D62B8F708100DD4058 /* ExtraContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraContainer.swift; sourceTree = ""; }; + CEED45DE2B8F70BB00DD4058 /* ExtraViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraViewModel.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -254,6 +342,7 @@ 9E4382CB2B83737600C69708 /* Services */ = { isa = PBXGroup; children = ( + CEED457B2B8F69AE00DD4058 /* Day */, 9E4382CC2B83738800C69708 /* Auth */, ); path = Services; @@ -310,6 +399,8 @@ 9E53FB322B7F87BA00C55A45 /* Everyday */ = { isa = PBXGroup; children = ( + CEED457E2B8F6A7000DD4058 /* Entities */, + CEED45782B8F692A00DD4058 /* Helpers */, 9E4382CB2B83737600C69708 /* Services */, 9E53FB4A2B7F94C200C55A45 /* Modules */, 9E53FB492B7F94BA00C55A45 /* Extensions */, @@ -592,12 +683,12 @@ 9EE8AE222B7FB91E001D126F /* Notepad */ = { isa = PBXGroup; children = ( - 9EE8AE232B7FB930001D126F /* NotepadPresenter.swift */, - 9EE8AE242B7FB930001D126F /* NotepadRouter.swift */, - 9EE8AE252B7FB930001D126F /* NotepadViewController.swift */, - 9EE8AE262B7FB930001D126F /* NotepadProtocols.swift */, - 9EE8AE272B7FB930001D126F /* NotepadInteractor.swift */, - 9EE8AE282B7FB930001D126F /* NotepadContainer.swift */, + CEED45832B8F6B1A00DD4058 /* NotepadScene */, + CEED458B2B8F6DA400DD4058 /* TrainingScene */, + CEED459E2B8F6EDF00DD4058 /* ExerciseScene */, + CEED45AE2B8F6F6100DD4058 /* ResultsScene */, + CEED45C02B8F700600DD4058 /* TimerScene */, + CEED45D02B8F707400DD4058 /* ExtraScene */, ); path = Notepad; sourceTree = ""; @@ -615,6 +706,167 @@ path = Workout; sourceTree = ""; }; + CEED45782B8F692A00DD4058 /* Helpers */ = { + isa = PBXGroup; + children = ( + CEED45792B8F693E00DD4058 /* CustomError.swift */, + ); + path = Helpers; + sourceTree = ""; + }; + CEED457B2B8F69AE00DD4058 /* Day */ = { + isa = PBXGroup; + children = ( + CEED457C2B8F69C500DD4058 /* DayService.swift */, + ); + path = Day; + sourceTree = ""; + }; + CEED457E2B8F6A7000DD4058 /* Entities */ = { + isa = PBXGroup; + children = ( + CEED457F2B8F6A7B00DD4058 /* Workout.swift */, + CEED45812B8F6A8F00DD4058 /* User.swift */, + ); + path = Entities; + sourceTree = ""; + }; + CEED45832B8F6B1A00DD4058 /* NotepadScene */ = { + isa = PBXGroup; + children = ( + CEED45842B8F6B4400DD4058 /* Models */, + 9EE8AE232B7FB930001D126F /* NotepadPresenter.swift */, + 9EE8AE242B7FB930001D126F /* NotepadRouter.swift */, + 9EE8AE252B7FB930001D126F /* NotepadViewController.swift */, + CEED45872B8F6D4400DD4058 /* NotepadSectionHeaderView.swift */, + CEED45892B8F6D7500DD4058 /* NotepadTableViewCell.swift */, + 9EE8AE262B7FB930001D126F /* NotepadProtocols.swift */, + 9EE8AE272B7FB930001D126F /* NotepadInteractor.swift */, + 9EE8AE282B7FB930001D126F /* NotepadContainer.swift */, + ); + path = NotepadScene; + sourceTree = ""; + }; + CEED45842B8F6B4400DD4058 /* Models */ = { + isa = PBXGroup; + children = ( + CEED45852B8F6B6C00DD4058 /* NotepadViewModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + CEED458B2B8F6DA400DD4058 /* TrainingScene */ = { + isa = PBXGroup; + children = ( + CEED45982B8F6DD200DD4058 /* Models */, + CEED458C2B8F6DCE00DD4058 /* TrainingPresenter.swift */, + CEED458D2B8F6DCE00DD4058 /* TrainingRouter.swift */, + CEED458E2B8F6DCE00DD4058 /* TrainingViewController.swift */, + CEED459B2B8F6E2700DD4058 /* TrainingTableViewCell.swift */, + CEED458F2B8F6DCE00DD4058 /* TrainingProtocols.swift */, + CEED45902B8F6DCE00DD4058 /* TrainingInteractor.swift */, + CEED45912B8F6DCE00DD4058 /* TrainingContainer.swift */, + ); + path = TrainingScene; + sourceTree = ""; + }; + CEED45982B8F6DD200DD4058 /* Models */ = { + isa = PBXGroup; + children = ( + CEED45992B8F6DE200DD4058 /* TrainingViewModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + CEED459E2B8F6EDF00DD4058 /* ExerciseScene */ = { + isa = PBXGroup; + children = ( + CEED45AB2B8F6EF900DD4058 /* Models */, + CEED459F2B8F6EF500DD4058 /* ExercisePresenter.swift */, + CEED45A02B8F6EF500DD4058 /* ExerciseRouter.swift */, + CEED45A12B8F6EF500DD4058 /* ExerciseViewController.swift */, + CEED45A22B8F6EF500DD4058 /* ExerciseProtocols.swift */, + CEED45A32B8F6EF500DD4058 /* ExerciseInteractor.swift */, + CEED45A42B8F6EF500DD4058 /* ExerciseContainer.swift */, + ); + path = ExerciseScene; + sourceTree = ""; + }; + CEED45AB2B8F6EF900DD4058 /* Models */ = { + isa = PBXGroup; + children = ( + CEED45AC2B8F6F0500DD4058 /* ExerciseViewModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + CEED45AE2B8F6F6100DD4058 /* ResultsScene */ = { + isa = PBXGroup; + children = ( + CEED45BB2B8F6F9700DD4058 /* Models */, + CEED45AF2B8F6F9300DD4058 /* ResultsPresenter.swift */, + CEED45B02B8F6F9300DD4058 /* ResultsRouter.swift */, + CEED45B12B8F6F9300DD4058 /* ResultsViewController.swift */, + CEED45BE2B8F6FDB00DD4058 /* ResultsTableViewCell.swift */, + CEED45B22B8F6F9300DD4058 /* ResultsProtocols.swift */, + CEED45B32B8F6F9300DD4058 /* ResultsInteractor.swift */, + CEED45B42B8F6F9300DD4058 /* ResultsContainer.swift */, + ); + path = ResultsScene; + sourceTree = ""; + }; + CEED45BB2B8F6F9700DD4058 /* Models */ = { + isa = PBXGroup; + children = ( + CEED45BC2B8F6FA300DD4058 /* ResultsViewModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + CEED45C02B8F700600DD4058 /* TimerScene */ = { + isa = PBXGroup; + children = ( + CEED45CD2B8F701E00DD4058 /* Models */, + CEED45C12B8F701800DD4058 /* TimerPresenter.swift */, + CEED45C22B8F701800DD4058 /* TimerRouter.swift */, + CEED45C32B8F701800DD4058 /* TimerViewController.swift */, + CEED45C42B8F701800DD4058 /* TimerProtocols.swift */, + CEED45C52B8F701800DD4058 /* TimerInteractor.swift */, + CEED45C62B8F701800DD4058 /* TimerContainer.swift */, + ); + path = TimerScene; + sourceTree = ""; + }; + CEED45CD2B8F701E00DD4058 /* Models */ = { + isa = PBXGroup; + children = ( + CEED45CE2B8F702800DD4058 /* TimerViewModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + CEED45D02B8F707400DD4058 /* ExtraScene */ = { + isa = PBXGroup; + children = ( + CEED45DD2B8F70AE00DD4058 /* Models */, + CEED45D12B8F708100DD4058 /* ExtraPresenter.swift */, + CEED45D22B8F708100DD4058 /* ExtraRouter.swift */, + CEED45D32B8F708100DD4058 /* ExtraViewController.swift */, + CEED45D42B8F708100DD4058 /* ExtraProtocols.swift */, + CEED45D52B8F708100DD4058 /* ExtraInteractor.swift */, + CEED45D62B8F708100DD4058 /* ExtraContainer.swift */, + ); + path = ExtraScene; + sourceTree = ""; + }; + CEED45DD2B8F70AE00DD4058 /* Models */ = { + isa = PBXGroup; + children = ( + CEED45DE2B8F70BB00DD4058 /* ExtraViewModel.swift */, + ); + path = Models; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -682,6 +934,7 @@ 9E673DA42B8275680041B97D /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */, 9E4382D72B83746B00C69708 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */, 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + CEED459D2B8F6EB100DD4058 /* XCRemoteSwiftPackageReference "M13Checkbox" */, ); productRefGroup = 9E53FB312B7F87BA00C55A45 /* Products */; projectDirPath = ""; @@ -733,31 +986,49 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CEED45A52B8F6EF500DD4058 /* ExercisePresenter.swift in Sources */, + CEED45BA2B8F6F9300DD4058 /* ResultsContainer.swift in Sources */, + CEED45DB2B8F708100DD4058 /* ExtraInteractor.swift in Sources */, + CEED45BF2B8F6FDB00DD4058 /* ResultsTableViewCell.swift in Sources */, + CEED45DF2B8F70BB00DD4058 /* ExtraViewModel.swift in Sources */, + CEED45A72B8F6EF500DD4058 /* ExerciseViewController.swift in Sources */, 9E5B75482B7F9D7600E2BDE6 /* ProfileAcknowledgementViewModel.swift in Sources */, 9E5B74F82B7F9A7000E2BDE6 /* SignUpInteractor.swift in Sources */, + CEED45CB2B8F701800DD4058 /* TimerInteractor.swift in Sources */, + CEED45C72B8F701800DD4058 /* TimerPresenter.swift in Sources */, 9E2A8BD12B8543DD004A81CF /* SignUpModel.swift in Sources */, 9E5B754D2B7F9D7600E2BDE6 /* ProfileSetupView.swift in Sources */, 9EE8AE072B7FB77D001D126F /* TabBarController.swift in Sources */, + CEED45A82B8F6EF500DD4058 /* ExerciseProtocols.swift in Sources */, 9E2A8BCF2B854147004A81CF /* Validator.swift in Sources */, 9EE8AE102B7FB8CF001D126F /* SettingsRouter.swift in Sources */, + CEED45962B8F6DCE00DD4058 /* TrainingInteractor.swift in Sources */, 9E5B753E2B7F9D7600E2BDE6 /* WeightViewModel.swift in Sources */, 9EE8AE212B7FB905001D126F /* ProgressContainer.swift in Sources */, 9E5B74FC2B7F9A7000E2BDE6 /* SignUpViewModel.swift in Sources */, 9EE8AE2A2B7FB930001D126F /* NotepadRouter.swift in Sources */, 9E5B74ED2B7F99FB00E2BDE6 /* WelcomeScreenViewModel.swift in Sources */, 9E5B75382B7F9D7600E2BDE6 /* GenderModel.swift in Sources */, + CEED45822B8F6A8F00DD4058 /* User.swift in Sources */, 9E5B754B2B7F9D7600E2BDE6 /* ProfileSetupViewModel.swift in Sources */, 9EE8AE2B2B7FB930001D126F /* NotepadViewController.swift in Sources */, 9E5B75422B7F9D7600E2BDE6 /* AgeController.swift in Sources */, 9EE8AE1E2B7FB905001D126F /* ProgressViewController.swift in Sources */, 9EE8AE392B7FB96E001D126F /* WorkoutProtocols.swift in Sources */, 9EE8AE132B7FB8CF001D126F /* SettingsInteractor.swift in Sources */, + CEED45AD2B8F6F0500DD4058 /* ExerciseViewModel.swift in Sources */, + CEED45862B8F6B6C00DD4058 /* NotepadViewModel.swift in Sources */, + CEED458A2B8F6D7500DD4058 /* NotepadTableViewCell.swift in Sources */, 9E5B74F92B7F9A7000E2BDE6 /* SignUpRouter.swift in Sources */, + CEED459A2B8F6DE200DD4058 /* TrainingViewModel.swift in Sources */, + CEED45D82B8F708100DD4058 /* ExtraRouter.swift in Sources */, 9E5B75112B7F9CE300E2BDE6 /* ImagePickerView.swift in Sources */, 9E53FB522B7F951400C55A45 /* String+Extension.swift in Sources */, 9E5B74EA2B7F99FB00E2BDE6 /* WelcomeScreenRouter.swift in Sources */, + CEED45802B8F6A7B00DD4058 /* Workout.swift in Sources */, 9E5B753A2B7F9D7600E2BDE6 /* GenderViewModel.swift in Sources */, 9E5B75092B7F9A8300E2BDE6 /* SignInRouter.swift in Sources */, + CEED45A62B8F6EF500DD4058 /* ExerciseRouter.swift in Sources */, 9E5B753B2B7F9D7600E2BDE6 /* GenderController.swift in Sources */, 9E4382D32B83738800C69708 /* InfoPlist.swift in Sources */, 9E5B74E92B7F99FB00E2BDE6 /* WelcomeScreenContainer.swift in Sources */, @@ -768,17 +1039,26 @@ 9E5B74EC2B7F99FB00E2BDE6 /* WelcomeScreenViewController.swift in Sources */, 9EE8AE362B7FB96E001D126F /* WorkoutPresenter.swift in Sources */, 9E5B75102B7F9CE300E2BDE6 /* UserTextFieldView.swift in Sources */, + CEED45C82B8F701800DD4058 /* TimerRouter.swift in Sources */, + CEED45BD2B8F6FA300DD4058 /* ResultsViewModel.swift in Sources */, 9EE8AE112B7FB8CF001D126F /* SettingsViewController.swift in Sources */, 9E5B75082B7F9A8300E2BDE6 /* SignInContainer.swift in Sources */, 9EE8AE3B2B7FB96E001D126F /* WorkoutContainer.swift in Sources */, + CEED45DA2B8F708100DD4058 /* ExtraProtocols.swift in Sources */, 9E4382D62B83738800C69708 /* GoogleAuthService.swift in Sources */, 9EE8AE1C2B7FB905001D126F /* ProgressPresenter.swift in Sources */, + CEED45B52B8F6F9300DD4058 /* ResultsPresenter.swift in Sources */, 9EE8AE1D2B7FB905001D126F /* ProgressRouter.swift in Sources */, + CEED459C2B8F6E2700DD4058 /* TrainingTableViewCell.swift in Sources */, + CEED45CF2B8F702800DD4058 /* TimerViewModel.swift in Sources */, + CEED45A92B8F6EF500DD4058 /* ExerciseInteractor.swift in Sources */, 9EE8AE382B7FB96E001D126F /* WorkoutViewController.swift in Sources */, 9EE8AE2E2B7FB930001D126F /* NotepadContainer.swift in Sources */, + CEED45D72B8F708100DD4058 /* ExtraPresenter.swift in Sources */, 9E5B753C2B7F9D7600E2BDE6 /* ContentView.swift in Sources */, 9E5B75452B7F9D7600E2BDE6 /* AgeView.swift in Sources */, 9E5B75072B7F9A8300E2BDE6 /* SignInProtocols.swift in Sources */, + CEED45942B8F6DCE00DD4058 /* TrainingViewController.swift in Sources */, 9E5B75472B7F9D7600E2BDE6 /* ProfileAcknowledgementModel.swift in Sources */, 9E7C19992B8CC3E80006D48C /* NameGenerator.swift in Sources */, 9E5B74FA2B7F9A7000E2BDE6 /* SignUpProtocols.swift in Sources */, @@ -789,12 +1069,17 @@ 9EE8AE292B7FB930001D126F /* NotepadPresenter.swift in Sources */, 9E53FB342B7F87BA00C55A45 /* AppDelegate.swift in Sources */, 9E5B75162B7F9D3500E2BDE6 /* GenderButtonView.swift in Sources */, + CEED45CA2B8F701800DD4058 /* TimerProtocols.swift in Sources */, 9E4382D42B83738800C69708 /* VKIDAuthService.swift in Sources */, 9E5B75442B7F9D7600E2BDE6 /* AgeViewModel.swift in Sources */, + CEED45B92B8F6F9300DD4058 /* ResultsInteractor.swift in Sources */, 9E5B74EB2B7F99FB00E2BDE6 /* WelcomeScreenProtocols.swift in Sources */, + CEED45972B8F6DCE00DD4058 /* TrainingContainer.swift in Sources */, 9E5B754A2B7F9D7600E2BDE6 /* OnBoardingViewController.swift in Sources */, 9E2A8BCD2B8520B2004A81CF /* AlertManager.swift in Sources */, + CEED45D92B8F708100DD4058 /* ExtraViewController.swift in Sources */, 9E5B75492B7F9D7600E2BDE6 /* ProfileAcknowledgementController.swift in Sources */, + CEED45922B8F6DCE00DD4058 /* TrainingPresenter.swift in Sources */, 9EE8AE3A2B7FB96E001D126F /* WorkoutInteractor.swift in Sources */, 9EE8AE122B7FB8CF001D126F /* SettingsProtocols.swift in Sources */, 9E5B75412B7F9D7600E2BDE6 /* PageView.swift in Sources */, @@ -803,21 +1088,33 @@ 9E5B750D2B7F9A8300E2BDE6 /* SignInPresenter.swift in Sources */, 9E5B75462B7F9D7600E2BDE6 /* ProfileAcknowledgementView.swift in Sources */, 9E5B753D2B7F9D7600E2BDE6 /* TextFieldView.swift in Sources */, + CEED45B82B8F6F9300DD4058 /* ResultsProtocols.swift in Sources */, + CEED45B72B8F6F9300DD4058 /* ResultsViewController.swift in Sources */, 9EE8AE0F2B7FB8CF001D126F /* SettingsPresenter.swift in Sources */, + CEED45DC2B8F708100DD4058 /* ExtraContainer.swift in Sources */, + CEED45932B8F6DCE00DD4058 /* TrainingRouter.swift in Sources */, 9E7C19972B8BF1340006D48C /* PasswordGenerator.swift in Sources */, 9E53FB362B7F87BA00C55A45 /* SceneDelegate.swift in Sources */, + CEED457A2B8F693E00DD4058 /* CustomError.swift in Sources */, + CEED45CC2B8F701800DD4058 /* TimerContainer.swift in Sources */, + CEED45C92B8F701800DD4058 /* TimerViewController.swift in Sources */, 9E5B74FD2B7F9A7000E2BDE6 /* SignUpContainer.swift in Sources */, 9E5B750B2B7F9A8300E2BDE6 /* SignInViewModel.swift in Sources */, 9EE8AE2D2B7FB930001D126F /* NotepadInteractor.swift in Sources */, 9E5B750C2B7F9A8300E2BDE6 /* SignInInteractor.swift in Sources */, + CEED45882B8F6D4400DD4058 /* NotepadSectionHeaderView.swift in Sources */, + CEED457D2B8F69C500DD4058 /* DayService.swift in Sources */, 9E5B75432B7F9D7600E2BDE6 /* AgeModel.swift in Sources */, + CEED45AA2B8F6EF500DD4058 /* ExerciseContainer.swift in Sources */, 9E5B75392B7F9D7600E2BDE6 /* GenderView.swift in Sources */, 9E5B74FB2B7F9A7000E2BDE6 /* SignUpPresenter.swift in Sources */, 9E5B750A2B7F9A8300E2BDE6 /* SignInViewController.swift in Sources */, 9E5B75142B7F9D1D00E2BDE6 /* AgeButtonView.swift in Sources */, 9EE8AE1F2B7FB905001D126F /* ProgressProtocols.swift in Sources */, + CEED45B62B8F6F9300DD4058 /* ResultsRouter.swift in Sources */, 9E5B753F2B7F9D7600E2BDE6 /* WeightView.swift in Sources */, 9E5B754C2B7F9D7600E2BDE6 /* ProfileSetupModel.swift in Sources */, + CEED45952B8F6DCE00DD4058 /* TrainingProtocols.swift in Sources */, 9EE8AE2C2B7FB930001D126F /* NotepadProtocols.swift in Sources */, 9E5B74EE2B7F99FB00E2BDE6 /* WelcomeScreenPresenter.swift in Sources */, ); @@ -1086,6 +1383,14 @@ minimumVersion = 1.2.2; }; }; + CEED459D2B8F6EB100DD4058 /* XCRemoteSwiftPackageReference "M13Checkbox" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Marxon13/M13Checkbox"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.0.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ diff --git a/Everyday/Entities/User.swift b/Everyday/Entities/User.swift new file mode 100644 index 0000000..8964021 --- /dev/null +++ b/Everyday/Entities/User.swift @@ -0,0 +1,30 @@ +// +// User.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import Foundation + +struct User { + let info: String // change for several properies: name, weight, etc. + let schedule: Schedule +} + +struct Schedule { + let daysOfWeek: [[(workout: Workout, indexOfDay: Int)]] // 7 elements (arrays) = 7 days +} + +struct MockSchedule { + + static let mockSchedule = Schedule(daysOfWeek: [ + [], + [], + [], + [], + [(workout: Mock.mockWorkouts[0], indexOfDay: 0), (workout: Mock.mockWorkouts[1], indexOfDay: 0)], + [(workout: Mock.mockWorkouts[2], indexOfDay: 0)], + [(workout: Mock.mockWorkouts[0], indexOfDay: 1)] + ]) +} diff --git a/Everyday/Entities/Workout.swift b/Everyday/Entities/Workout.swift new file mode 100644 index 0000000..1ac1941 --- /dev/null +++ b/Everyday/Entities/Workout.swift @@ -0,0 +1,68 @@ +// +// Workout.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import Foundation + +struct Workout { + let name: String + var days: [DayOfWorkout] +} + +struct DayOfWorkout { + var name: String + var sets: [TrainingSet] +} + +struct TrainingSet { + var name: String + var exercises: [Exercise] +} + +struct Exercise { + let name: String + let description: String + var result: String // change for enum ResultOfExercise, problem: set 0 by default? +} + +// not in use yet +enum ResultOfExercise { + case reps(Int, Int) // associated values: number of reps, extra weight (zero by default or another case) + case time(Int, Int, Int) // associated values: minutes, seconds, extra weight (zero by default or another case) +} + +struct Mock { + + static let mockWorkouts = [ + Workout(name: "Фулбоди", days: [ + DayOfWorkout(name: "День 1", sets: [ + TrainingSet(name: "", exercises: [ + Exercise(name: "Подтягивания", description: "", result: "10"), + Exercise(name: "Отжимания", description: "", result: "20")]), + TrainingSet(name: "", exercises: [ + Exercise(name: "Пресс", description: "", result: "11"), + Exercise(name: "Спина", description: "", result: "22")])]), + DayOfWorkout(name: "День 2", sets: [ + TrainingSet(name: "", exercises: [ + Exercise(name: "епуапук", description: "", result: "10 раз"), + Exercise(name: "куцпкцпц", description: "", result: "20 раз")]), + TrainingSet(name: "", exercises: [ + Exercise(name: "кцпук", description: "", result: "1 минута"), + Exercise(name: "куцпукп", description: "", result: "20 раз")])])]), + Workout(name: "Руки", days: [ + DayOfWorkout(name: "День 1", sets: [ + TrainingSet(name: "", exercises: [ + Exercise(name: "Фокусы", description: "", result: "10 попугаев")])])]), + Workout(name: "Ноги", days: [ + DayOfWorkout(name: "День 1", sets: [ + TrainingSet(name: "", exercises: [ + Exercise(name: "Штанга", description: "", result: "8 раз")])])]), + Workout(name: "Кардио", days: [ + DayOfWorkout(name: "День 1", sets: [ + TrainingSet(name: "", exercises: [ + Exercise(name: "Jumping Jacks", description: "", result: "20 раз")])])]), + ] +} diff --git a/Everyday/Extensions/UIColor+Extension.swift b/Everyday/Extensions/UIColor+Extension.swift index 842d3b6..40da51a 100644 --- a/Everyday/Extensions/UIColor+Extension.swift +++ b/Everyday/Extensions/UIColor+Extension.swift @@ -39,14 +39,14 @@ extension UIColor { guard let color = UIColor(named: "SpaceGray") else { fatalError("Can't find color: SpaceGray") } - return color - }() - - static let grayElement: UIColor = { - guard let color = UIColor(named: "GrayElements") else { - fatalError("Can't find color: Snow") - } - return color - }() - } + return color + }() + + static let grayElement: UIColor = { + guard let color = UIColor(named: "GrayElements") else { + fatalError("Can't find color: Snow") + } + return color + }() + } } diff --git a/Everyday/Extensions/UIView+Extension.swift b/Everyday/Extensions/UIView+Extension.swift index 28573c3..7736370 100644 --- a/Everyday/Extensions/UIView+Extension.swift +++ b/Everyday/Extensions/UIView+Extension.swift @@ -8,7 +8,6 @@ import UIKit extension UIView { - func addSubviews(_ views: UIView...) { for view in views { addSubview(view) diff --git a/Everyday/Helpers/CustomError.swift b/Everyday/Helpers/CustomError.swift new file mode 100644 index 0000000..ea92c59 --- /dev/null +++ b/Everyday/Helpers/CustomError.swift @@ -0,0 +1,12 @@ +// +// CustomError.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import Foundation + +enum CustomError: String, Error { + case unknownError = "Неопределнная ошибка" +} diff --git a/Everyday/Modules/Notepad/ExerciseScene/ExerciseContainer.swift b/Everyday/Modules/Notepad/ExerciseScene/ExerciseContainer.swift new file mode 100644 index 0000000..f086f15 --- /dev/null +++ b/Everyday/Modules/Notepad/ExerciseScene/ExerciseContainer.swift @@ -0,0 +1,43 @@ +// +// ExerciseContainer.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class ExerciseContainer { + let input: ExerciseModuleInput + let viewController: UIViewController + private(set) weak var router: ExerciseRouterInput! + + class func assemble(with context: ExerciseContext) -> ExerciseContainer { + let router = ExerciseRouter() + let interactor = ExerciseInteractor() + let presenter = ExercisePresenter(router: router, interactor: interactor, exercise: context.exercise, indexOfSet: context.indexOfSet) + let viewController = ExerciseViewController(output: presenter) + + presenter.view = viewController + presenter.moduleOutput = context.moduleOutput + + interactor.output = presenter + + router.viewController = viewController + + return ExerciseContainer(view: viewController, input: presenter, router: router) + } + + private init(view: UIViewController, input: ExerciseModuleInput, router: ExerciseRouterInput) { + self.viewController = view + self.input = input + self.router = router + } +} + +struct ExerciseContext { + weak var moduleOutput: ExerciseModuleOutput? + let exercise: Exercise + let indexOfSet: Int +} diff --git a/Everyday/Modules/Notepad/ExerciseScene/ExerciseInteractor.swift b/Everyday/Modules/Notepad/ExerciseScene/ExerciseInteractor.swift new file mode 100644 index 0000000..11f3a77 --- /dev/null +++ b/Everyday/Modules/Notepad/ExerciseScene/ExerciseInteractor.swift @@ -0,0 +1,16 @@ +// +// ExerciseInteractor.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class ExerciseInteractor { + weak var output: ExerciseInteractorOutput? +} + +extension ExerciseInteractor: ExerciseInteractorInput { +} diff --git a/Everyday/Modules/Notepad/ExerciseScene/ExercisePresenter.swift b/Everyday/Modules/Notepad/ExerciseScene/ExercisePresenter.swift new file mode 100644 index 0000000..cc96647 --- /dev/null +++ b/Everyday/Modules/Notepad/ExerciseScene/ExercisePresenter.swift @@ -0,0 +1,51 @@ +// +// ExercisePresenter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class ExercisePresenter { + weak var view: ExerciseViewInput? + weak var moduleOutput: ExerciseModuleOutput? + + private let router: ExerciseRouterInput + private let interactor: ExerciseInteractorInput + + private var exercise: Exercise + private var indexOfSet: Int + private var result: String = "0" + + init(router: ExerciseRouterInput, interactor: ExerciseInteractorInput, exercise: Exercise, indexOfSet: Int) { + self.router = router + self.interactor = interactor + self.exercise = exercise + self.indexOfSet = indexOfSet + } +} + +extension ExercisePresenter: ExerciseModuleInput { +} + +extension ExercisePresenter: ExerciseViewOutput { + func didLoadView() { + let viewModel = ExerciseViewModel(exercise: exercise) + view?.configure(with: viewModel) + } + + func didTapStepper(with result: String) { + self.result = result + view?.updateResult(with: result) + } + + func didTapSaveButton() { + moduleOutput?.setResult(of: exercise.name, with: result, at: indexOfSet) + router.closeExercise() + } +} + +extension ExercisePresenter: ExerciseInteractorOutput { +} diff --git a/Everyday/Modules/Notepad/ExerciseScene/ExerciseProtocols.swift b/Everyday/Modules/Notepad/ExerciseScene/ExerciseProtocols.swift new file mode 100644 index 0000000..cfec808 --- /dev/null +++ b/Everyday/Modules/Notepad/ExerciseScene/ExerciseProtocols.swift @@ -0,0 +1,38 @@ +// +// ExerciseProtocols.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +protocol ExerciseModuleInput { + var moduleOutput: ExerciseModuleOutput? { get } +} + +protocol ExerciseModuleOutput: AnyObject { + func setResult(of exercise: String, with result: String, at indexOfSet: Int) +} + +protocol ExerciseViewInput: AnyObject { + func configure(with viewModel: ExerciseViewModel) + func updateResult(with result: String) +} + +protocol ExerciseViewOutput: AnyObject { + func didLoadView() + func didTapStepper(with result: String) + func didTapSaveButton() +} + +protocol ExerciseInteractorInput: AnyObject { +} + +protocol ExerciseInteractorOutput: AnyObject { +} + +protocol ExerciseRouterInput: AnyObject { + func closeExercise() +} diff --git a/Everyday/Modules/Notepad/ExerciseScene/ExerciseRouter.swift b/Everyday/Modules/Notepad/ExerciseScene/ExerciseRouter.swift new file mode 100644 index 0000000..0e4b891 --- /dev/null +++ b/Everyday/Modules/Notepad/ExerciseScene/ExerciseRouter.swift @@ -0,0 +1,26 @@ +// +// ExerciseRouter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class ExerciseRouter { + weak var viewController: ExerciseViewController? +} + +extension ExerciseRouter: ExerciseRouterInput { + func closeExercise() { + guard + let viewController = viewController, + let navigationController = viewController.navigationController + else { + return + } + + navigationController.popViewController(animated: true) + } +} diff --git a/Everyday/Modules/Notepad/ExerciseScene/ExerciseViewController.swift b/Everyday/Modules/Notepad/ExerciseScene/ExerciseViewController.swift new file mode 100644 index 0000000..470ca67 --- /dev/null +++ b/Everyday/Modules/Notepad/ExerciseScene/ExerciseViewController.swift @@ -0,0 +1,128 @@ +// +// ExerciseViewController.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit +import PinLayout + +final class ExerciseViewController: UIViewController { + + // MARK: - Private properties + + private let output: ExerciseViewOutput + + private let resultLabel = UILabel() + private let counterStepper = UIStepper() + private let saveButton = UIButton() + + // MARK: - Init + + init(output: ExerciseViewOutput) { + self.output = output + + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + output.didLoadView() + setup() + } + + override func viewDidLayoutSubviews() { + layout() + } +} + +private extension ExerciseViewController { + + // MARK: - Layout + + func layout() { + resultLabel.pin + .top(view.pin.safeArea) + .marginTop(300) + .horizontally(20) + .height(30) + + counterStepper.pin + .below(of: resultLabel) + .hCenter() + .width(100) + .height(40) + + saveButton.pin + .below(of: counterStepper) + .marginTop(40) + .hCenter() + .width(100) + .height(40) + } + + // MARK: - Setup + + func setup() { + setupView() + setupResultLabel() + setupStepper() + setupButton() + + view.addSubviews(resultLabel, counterStepper, saveButton) + } + + func setupView() { + view.backgroundColor = .systemBackground + } + + func setupResultLabel() { + resultLabel.textAlignment = .center + } + + func setupStepper() { + counterStepper.addTarget(self, action: #selector(didTapStepper), for: .touchUpInside) + } + + func setupButton() { + saveButton.backgroundColor = .systemBlue + saveButton.addTarget(self, action: #selector(didTapSaveButton), for: .touchUpInside) + } + + // MARK: - Actions + + @objc + func didTapStepper() { + let counterValue = Int(counterStepper.value).description + output.didTapStepper(with: counterValue) + } + + @objc + func didTapSaveButton() { + output.didTapSaveButton() + } +} + +// MARK: - ExerciseViewInput + +extension ExerciseViewController: ExerciseViewInput { + func configure(with viewModel: ExerciseViewModel) { + title = viewModel.title + resultLabel.attributedText = viewModel.resultTitle + saveButton.setAttributedTitle(viewModel.saveTitle, for: .normal) + } + + func updateResult(with result: String) { + resultLabel.text = result + } +} diff --git a/Everyday/Modules/Notepad/ExerciseScene/Models/ExerciseViewModel.swift b/Everyday/Modules/Notepad/ExerciseScene/Models/ExerciseViewModel.swift new file mode 100644 index 0000000..b307981 --- /dev/null +++ b/Everyday/Modules/Notepad/ExerciseScene/Models/ExerciseViewModel.swift @@ -0,0 +1,33 @@ +// +// ExerciseViewModel.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit + +struct ExerciseViewModel { + let title: String + let resultTitle: NSAttributedString + let saveTitle: NSAttributedString + + init(exercise: Exercise) { + let resultLabelTitle = "0" + let resultLabelAttributedString = NSAttributedString(string: resultLabelTitle, attributes: Styles.titleAttributes) + let saveButtonTitle = "Сохранить" + let saveButtonAttributedString = NSAttributedString(string: saveButtonTitle, attributes: Styles.titleAttributes) + + self.title = exercise.name + self.resultTitle = resultLabelAttributedString + self.saveTitle = saveButtonAttributedString + } +} + +private extension ExerciseViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/ExtraScene/ExtraContainer.swift b/Everyday/Modules/Notepad/ExtraScene/ExtraContainer.swift new file mode 100644 index 0000000..856050e --- /dev/null +++ b/Everyday/Modules/Notepad/ExtraScene/ExtraContainer.swift @@ -0,0 +1,39 @@ +// +// ExtraContainer.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class ExtraContainer { + let input: ExtraModuleInput + let viewController: UIViewController + private(set) weak var router: ExtraRouterInput! + + class func assemble(with context: ExtraContext) -> ExtraContainer { + let router = ExtraRouter() + let interactor = ExtraInteractor() + let presenter = ExtraPresenter(router: router, interactor: interactor) + let viewController = ExtraViewController(output: presenter) + + presenter.view = viewController + presenter.moduleOutput = context.moduleOutput + + interactor.output = presenter + + return ExtraContainer(view: viewController, input: presenter, router: router) + } + + private init(view: UIViewController, input: ExtraModuleInput, router: ExtraRouterInput) { + self.viewController = view + self.input = input + self.router = router + } +} + +struct ExtraContext { + weak var moduleOutput: ExtraModuleOutput? +} diff --git a/Everyday/Modules/Notepad/ExtraScene/ExtraInteractor.swift b/Everyday/Modules/Notepad/ExtraScene/ExtraInteractor.swift new file mode 100644 index 0000000..7eaa5c3 --- /dev/null +++ b/Everyday/Modules/Notepad/ExtraScene/ExtraInteractor.swift @@ -0,0 +1,16 @@ +// +// ExtraInteractor.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class ExtraInteractor { + weak var output: ExtraInteractorOutput? +} + +extension ExtraInteractor: ExtraInteractorInput { +} diff --git a/Everyday/Modules/Notepad/ExtraScene/ExtraPresenter.swift b/Everyday/Modules/Notepad/ExtraScene/ExtraPresenter.swift new file mode 100644 index 0000000..2cf5436 --- /dev/null +++ b/Everyday/Modules/Notepad/ExtraScene/ExtraPresenter.swift @@ -0,0 +1,31 @@ +// +// ExtraPresenter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class ExtraPresenter { + weak var view: ExtraViewInput? + weak var moduleOutput: ExtraModuleOutput? + + private let router: ExtraRouterInput + private let interactor: ExtraInteractorInput + + init(router: ExtraRouterInput, interactor: ExtraInteractorInput) { + self.router = router + self.interactor = interactor + } +} + +extension ExtraPresenter: ExtraModuleInput { +} + +extension ExtraPresenter: ExtraViewOutput { +} + +extension ExtraPresenter: ExtraInteractorOutput { +} diff --git a/Everyday/Modules/Notepad/ExtraScene/ExtraProtocols.swift b/Everyday/Modules/Notepad/ExtraScene/ExtraProtocols.swift new file mode 100644 index 0000000..d30d2ea --- /dev/null +++ b/Everyday/Modules/Notepad/ExtraScene/ExtraProtocols.swift @@ -0,0 +1,31 @@ +// +// ExtraProtocols.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +protocol ExtraModuleInput { + var moduleOutput: ExtraModuleOutput? { get } +} + +protocol ExtraModuleOutput: AnyObject { +} + +protocol ExtraViewInput: AnyObject { +} + +protocol ExtraViewOutput: AnyObject { +} + +protocol ExtraInteractorInput: AnyObject { +} + +protocol ExtraInteractorOutput: AnyObject { +} + +protocol ExtraRouterInput: AnyObject { +} diff --git a/Everyday/Modules/Notepad/ExtraScene/ExtraRouter.swift b/Everyday/Modules/Notepad/ExtraScene/ExtraRouter.swift new file mode 100644 index 0000000..cc39656 --- /dev/null +++ b/Everyday/Modules/Notepad/ExtraScene/ExtraRouter.swift @@ -0,0 +1,15 @@ +// +// ExtraRouter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class ExtraRouter { +} + +extension ExtraRouter: ExtraRouterInput { +} diff --git a/Everyday/Modules/Notepad/ExtraScene/ExtraViewController.swift b/Everyday/Modules/Notepad/ExtraScene/ExtraViewController.swift new file mode 100644 index 0000000..54050da --- /dev/null +++ b/Everyday/Modules/Notepad/ExtraScene/ExtraViewController.swift @@ -0,0 +1,51 @@ +// +// ExtraViewController.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class ExtraViewController: UIViewController { + + // MARK: - Private properties + + private let output: ExtraViewOutput + + // MARK: - Init + + init(output: ExtraViewOutput) { + self.output = output + + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + setup() + } +} + +private extension ExtraViewController { + + // MARK: - Setup + + func setup() { + view.backgroundColor = .systemBackground + } +} + +// MARK: - ExtraViewInput + +extension ExtraViewController: ExtraViewInput { +} diff --git a/Everyday/Modules/Notepad/ExtraScene/Models/ExtraViewModel.swift b/Everyday/Modules/Notepad/ExtraScene/Models/ExtraViewModel.swift new file mode 100644 index 0000000..36a188b --- /dev/null +++ b/Everyday/Modules/Notepad/ExtraScene/Models/ExtraViewModel.swift @@ -0,0 +1,8 @@ +// +// ExtraViewModel.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import Foundation diff --git a/Everyday/Modules/Notepad/NotepadInteractor.swift b/Everyday/Modules/Notepad/NotepadInteractor.swift deleted file mode 100644 index b3c01b5..0000000 --- a/Everyday/Modules/Notepad/NotepadInteractor.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// NotepadInteractor.swift -// Everyday -// -// Created by Михаил on 16.02.2024. -// -// - -import Foundation - -final class NotepadInteractor { - weak var output: NotepadInteractorOutput? -} - -extension NotepadInteractor: NotepadInteractorInput { -} diff --git a/Everyday/Modules/Notepad/NotepadPresenter.swift b/Everyday/Modules/Notepad/NotepadPresenter.swift deleted file mode 100644 index 8960b49..0000000 --- a/Everyday/Modules/Notepad/NotepadPresenter.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// NotepadPresenter.swift -// Everyday -// -// Created by Михаил on 16.02.2024. -// -// - -import Foundation - -final class NotepadPresenter { - weak var view: NotepadViewInput? - weak var moduleOutput: NotepadModuleOutput? - - private let router: NotepadRouterInput - private let interactor: NotepadInteractorInput - - init(router: NotepadRouterInput, interactor: NotepadInteractorInput) { - self.router = router - self.interactor = interactor - } -} - -extension NotepadPresenter: NotepadModuleInput { -} - -extension NotepadPresenter: NotepadViewOutput { -} - -extension NotepadPresenter: NotepadInteractorOutput { -} diff --git a/Everyday/Modules/Notepad/NotepadProtocols.swift b/Everyday/Modules/Notepad/NotepadProtocols.swift deleted file mode 100644 index 9a8538e..0000000 --- a/Everyday/Modules/Notepad/NotepadProtocols.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// NotepadProtocols.swift -// Everyday -// -// Created by Михаил on 16.02.2024. -// -// - -import Foundation - -protocol NotepadModuleInput { - var moduleOutput: NotepadModuleOutput? { get } -} - -protocol NotepadModuleOutput: AnyObject { -} - -protocol NotepadViewInput: AnyObject { -} - -protocol NotepadViewOutput: AnyObject { -} - -protocol NotepadInteractorInput: AnyObject { -} - -protocol NotepadInteractorOutput: AnyObject { -} - -protocol NotepadRouterInput: AnyObject { -} diff --git a/Everyday/Modules/Notepad/NotepadRouter.swift b/Everyday/Modules/Notepad/NotepadRouter.swift deleted file mode 100644 index de2830f..0000000 --- a/Everyday/Modules/Notepad/NotepadRouter.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// NotepadRouter.swift -// Everyday -// -// Created by Михаил on 16.02.2024. -// -// - -import UIKit - -final class NotepadRouter { -} - -extension NotepadRouter: NotepadRouterInput { -} diff --git a/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift new file mode 100644 index 0000000..f8f7b3b --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift @@ -0,0 +1,27 @@ +// +// NotepadViewModel.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit + +struct NotepadViewModel { + let stateTitle: NSAttributedString + + init(isResult: Bool) { + let stateLabelTitle = isResult ? "Результат" : "Ваш план" + let stateLabelAttributedString = NSAttributedString(string: stateLabelTitle, attributes: Styles.titleAttributes) + + self.stateTitle = stateLabelAttributedString + } +} + +private extension NotepadViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .font: UIFont.systemFont(ofSize: 24, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/NotepadContainer.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadContainer.swift similarity index 95% rename from Everyday/Modules/Notepad/NotepadContainer.swift rename to Everyday/Modules/Notepad/NotepadScene/NotepadContainer.swift index 8c62e0d..d23a890 100644 --- a/Everyday/Modules/Notepad/NotepadContainer.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadContainer.swift @@ -24,6 +24,8 @@ final class NotepadContainer { interactor.output = presenter + router.viewController = viewController + return NotepadContainer(view: viewController, input: presenter, router: router) } diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift new file mode 100644 index 0000000..13f4b9d --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift @@ -0,0 +1,51 @@ +// +// NotepadInteractor.swift +// Everyday +// +// Created by Михаил on 16.02.2024. +// +// + +import Foundation + +final class NotepadInteractor { + weak var output: NotepadInteractorOutput? + private let dayManager: DayManagerDescription + + init(dayManager: DayManagerDescription = DayManager.shared) { + self.dayManager = dayManager + } +} + +extension NotepadInteractor: NotepadInteractorInput { + + func loadResult(date: Date) { + dayManager.getDayResults(on: date) { [weak self] result in + guard let self else { + return + } + + switch result { + case .success(let workoutDays): + self.output?.didLoadDay(with: workoutDays, true) + case .failure(let error): + self.loadSchedule() + } + } + } + + func loadSchedule() { + dayManager.getDaySchedule { [weak self] result in + guard let self else { + return + } + + switch result { + case .success(let workoutDays): + self.output?.didLoadDay(with: workoutDays, false) + case .failure(let error): + break + } + } + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadPresenter.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadPresenter.swift new file mode 100644 index 0000000..046cf85 --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadPresenter.swift @@ -0,0 +1,88 @@ +// +// NotepadPresenter.swift +// Everyday +// +// Created by Михаил on 16.02.2024. +// +// + +import Foundation + +final class NotepadPresenter { + weak var view: NotepadViewInput? + weak var moduleOutput: NotepadModuleOutput? + + private let router: NotepadRouterInput + private let interactor: NotepadInteractorInput + + private var isResult: Bool = false + private var workoutDays: [(workout: Workout, indexOfDay: Int)] = [] + private var isCollapsed = [ + true, + true + ] + + init(router: NotepadRouterInput, interactor: NotepadInteractorInput) { + self.router = router + self.interactor = interactor + } +} + +extension NotepadPresenter: NotepadModuleInput { +} + +extension NotepadPresenter: NotepadViewOutput { + func didLoadView() { + interactor.loadResult(date: Date()) + } + + func headerViewState() -> NotepadSectionHeaderState { + isResult ? .collapse : .open + } + + func getWorkoutDay(_ number: Int) -> (workout: Workout, indexOfDay: Int) { + (workoutDays[number]) + } + + func getWorkout(at indexOfWorkout: Int) -> Workout { + workoutDays[indexOfWorkout].workout + } + + func getExercises(at indexOfSection: Int) -> [Exercise] { + workoutDays[indexOfSection].workout.days[workoutDays[indexOfSection].indexOfDay].sets.flatMap { $0.exercises } + } + + func getExercise(at indexOfSection: Int, at indexOfRow: Int) -> Exercise { + workoutDays[indexOfSection].workout.days[workoutDays[indexOfSection].indexOfDay].sets.flatMap { $0.exercises }[indexOfRow] + } + + func numberOfSections() -> Int { + workoutDays.count + } + + func numberOfRowsInSection(_ section: Int) -> Int { + isCollapsed[section] ? 0 : workoutDays[section].workout.days[workoutDays[section].indexOfDay].sets.flatMap { $0.exercises }.count + } + + func toggleCollapsed(at indexOfSection: Int) -> Bool { + isCollapsed[indexOfSection] = !isCollapsed[indexOfSection] + return isCollapsed[indexOfSection] + } + + func didTapHeaderView(number: Int) { + let trainingContext = TrainingContext(workoutDay: workoutDays[number]) + router.openTraining(with: trainingContext) + } +} + +extension NotepadPresenter: NotepadInteractorOutput { + + func didLoadDay(with workoutDays: [(workout: Workout, indexOfDay: Int)], _ isResult: Bool) { + self.workoutDays = workoutDays + self.isResult = isResult + + let viewModel = NotepadViewModel(isResult: isResult) + view?.configure(with: viewModel) + view?.reloadData() + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadProtocols.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadProtocols.swift new file mode 100644 index 0000000..392bd0d --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadProtocols.swift @@ -0,0 +1,47 @@ +// +// NotepadProtocols.swift +// Everyday +// +// Created by Михаил on 16.02.2024. +// +// + +import Foundation + +protocol NotepadModuleInput { + var moduleOutput: NotepadModuleOutput? { get } +} + +protocol NotepadModuleOutput: AnyObject { +} + +protocol NotepadViewInput: AnyObject { + func configure(with viewModel: NotepadViewModel) + func reloadData() +} + +protocol NotepadViewOutput: AnyObject { + func didLoadView() + func headerViewState() -> NotepadSectionHeaderState + func getWorkoutDay(_ number: Int) -> (workout: Workout, indexOfDay: Int) + func getWorkout(at indexOfWorkout: Int) -> Workout + func getExercises(at indexOfSection: Int) -> [Exercise] + func getExercise(at indexOfSection: Int, at indexOfRow: Int) -> Exercise + func numberOfSections() -> Int + func numberOfRowsInSection(_ section: Int) -> Int + func toggleCollapsed(at indexOfSection: Int) -> Bool + func didTapHeaderView(number: Int) +} + +protocol NotepadInteractorInput: AnyObject { + func loadSchedule() + func loadResult(date: Date) +} + +protocol NotepadInteractorOutput: AnyObject { + func didLoadDay(with workoutDays: [(workout: Workout, indexOfDay: Int)], _ isResult: Bool) +} + +protocol NotepadRouterInput: AnyObject { + func openTraining(with trainingContext: TrainingContext) +} diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadRouter.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadRouter.swift new file mode 100644 index 0000000..73919ab --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadRouter.swift @@ -0,0 +1,27 @@ +// +// NotepadRouter.swift +// Everyday +// +// Created by Михаил on 16.02.2024. +// +// + +import UIKit + +final class NotepadRouter { + weak var viewController: NotepadViewController? +} + +extension NotepadRouter: NotepadRouterInput { + func openTraining(with trainingContext: TrainingContext) { + guard + let viewController = viewController, + let navigationController = viewController.navigationController + else { + return + } + + let trainingContainer = TrainingContainer.assemble(with: trainingContext) + navigationController.pushViewController(trainingContainer.viewController, animated: true) + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadSectionHeaderView.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadSectionHeaderView.swift new file mode 100644 index 0000000..e78d82b --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadSectionHeaderView.swift @@ -0,0 +1,122 @@ +// +// NotepadSectionHeaderView.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit +import PinLayout + +enum NotepadSectionHeaderState { + case open + case collapse +} + +class NotepadSectionHeaderView: UIView { + + // MARK: - Private properties + + private let titleLabel = UILabel() + private let descriptionLabel = UILabel() + private let collapseButton = UIButton() + + private var state: NotepadSectionHeaderState = .collapse + + // MARK: - Init + + override init(frame: CGRect) { + super.init(frame: frame) + + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func layoutSubviews() { + layout() + } + + // MARK: - Interface + + func configure(with workoutDay: (workout: Workout, indexOfDay: Int), and tag: Int, state: NotepadSectionHeaderState) { + titleLabel.text = workoutDay.workout.name + descriptionLabel.text = workoutDay.workout.days[workoutDay.indexOfDay].name + + self.tag = tag + collapseButton.tag = tag + self.state = state + } + + func addActions(_ target: Any?, viewAction: Selector, buttonAction: Selector) { + switch state { + case .open: + let tapGesture = UITapGestureRecognizer(target: target, action: viewAction) + self.addGestureRecognizer(tapGesture) + case .collapse: + collapseButton.addTarget(target, action: buttonAction, for: .touchUpInside) + } + } +} + +private extension NotepadSectionHeaderView { + + // MARK: - Layout + + func layout() { + let labelStackView = UIStackView(arrangedSubviews: [titleLabel, descriptionLabel]) + labelStackView.axis = .vertical + labelStackView.distribution = .equalSpacing + + let mainStackView = UIStackView(arrangedSubviews: [labelStackView, collapseButton]) + mainStackView.axis = .horizontal + mainStackView.distribution = .equalSpacing + + self.addSubview(mainStackView) + + mainStackView.pin + .horizontally(20) + .vertically(10) + } + + // MARK: - Setup + + func setup() { + setupView() + setupTitleLabel() + setupDescriptionLabel() + setupCollapseButton() + } + + func setupView() { + self.backgroundColor = .systemBackground + + self.layer.borderColor = UIColor.label.cgColor + self.layer.borderWidth = 1 + + self.layer.cornerRadius = 16 + self.layer.shadowColor = UIColor.black.cgColor + self.layer.shadowOpacity = 0.3 + self.layer.shadowOffset = .zero + } + + func setupTitleLabel() { + titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .regular) + titleLabel.textColor = .label + } + + func setupDescriptionLabel() { + descriptionLabel.font = UIFont.systemFont(ofSize: 16, weight: .regular) + descriptionLabel.textColor = .secondaryLabel + } + + func setupCollapseButton() { + let buttonImage = UIImage(systemName: "chevron.down") + collapseButton.setImage(buttonImage, for: .normal) + collapseButton.tintColor = .label + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadTableViewCell.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadTableViewCell.swift new file mode 100644 index 0000000..48055c0 --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadTableViewCell.swift @@ -0,0 +1,70 @@ +// +// NotepadTableViewCell.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit +import PinLayout + +class NotepadTableViewCell: UITableViewCell { + static let reuseID = "NotepadTableViewCell" + + // MARK: - Private properties + + private let titleLabel = UILabel() + private let resultLabel = UILabel() + + // MARK: - Init + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func layoutSubviews() { + layout() + } + + // MARK: - Interface + + func configure(with exercise: Exercise) { + titleLabel.text = exercise.name + resultLabel.text = exercise.result + } +} + +private extension NotepadTableViewCell { + + // MARK: - Layout + + func layout() { + titleLabel.pin + .left(10) + .vCenter() + .width(200) + .height(20) + + resultLabel.pin + .right(10) + .vCenter() + .width(100) + .height(20) + } + + // MARK: - Setup + + func setup() { + resultLabel.textAlignment = .center + + contentView.addSubviews(titleLabel, resultLabel) + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift new file mode 100644 index 0000000..009e7b0 --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift @@ -0,0 +1,188 @@ +// +// NotepadViewController.swift +// Everyday +// +// Created by Михаил on 16.02.2024. +// +// + +import UIKit +import PinLayout + +final class NotepadViewController: UIViewController { + + // MARK: - Private properties + + private let output: NotepadViewOutput + + private let stateLabel = UILabel() + private let tableView = UITableView(frame: .zero, style: .insetGrouped) + + // MARK: - Init + + init(output: NotepadViewOutput) { + self.output = output + + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + output.didLoadView() + setup() + } + + override func viewDidLayoutSubviews() { + layout() + } +} + +private extension NotepadViewController { + + // MARK: - Layout + + func layout() { + stateLabel.pin + .top(view.pin.safeArea).marginTop(200) + .horizontally(20) + .height(30) + + tableView.pin + .below(of: stateLabel) + .marginTop(10) + .horizontally() + .bottom() + } + + // MARK: - Setup + + func setup() { + setupView() + setupTableView() + + view.addSubviews(stateLabel, tableView) + } + + func setupView() { + view.backgroundColor = .systemBackground + navigationItem.leftBarButtonItem = UIBarButtonItem(customView: dateLabel()) + } + + func setupTableView() { + tableView.backgroundColor = .systemBackground + tableView.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0) + tableView.dataSource = self + tableView.delegate = self + tableView.register(NotepadTableViewCell.self, forCellReuseIdentifier: NotepadTableViewCell.reuseID) + } + + func dateLabel() -> UILabel { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "EEEE, MMM d" + dateFormatter.locale = Locale(identifier: "ru_RU") + + let currentDate = dateFormatter.string(from: Date()) + + let dateLabel = UILabel() + dateLabel.text = currentDate.capitalized + + return dateLabel + } + + // MARK: - Actions + + @objc + func didTapHeaderView(_ sender: UITapGestureRecognizer) { + guard let view = sender.view else { + return + } + + output.didTapHeaderView(number: view.tag) + } + + @objc + func didTapCollapseButton(_ button: UIButton) { + var indexPaths = [IndexPath]() + + let section = button.tag + let exercises = output.getExercises(at: section) + for exerciseIndex in 0.. Int { + output.numberOfSections() + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + output.numberOfRowsInSection(section) + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: NotepadTableViewCell.reuseID, for: indexPath) as? NotepadTableViewCell else { + return UITableViewCell() + } + + let exercise = output.getExercise(at: indexPath.section, at: indexPath.row) + cell.configure(with: exercise) + + return cell + } +} + +// MARK: - UITableViewDelegate + +extension NotepadViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView = NotepadSectionHeaderView() + + let workoutDay = output.getWorkoutDay(section) + let headerViewState = output.headerViewState() + headerView.configure(with: workoutDay, and: section, state: headerViewState) + headerView.addActions(self, viewAction: #selector(didTapHeaderView), buttonAction: #selector(didTapCollapseButton)) + + return headerView + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 60 + } +} + +// MARK: - NotepadViewInput + +extension NotepadViewController: NotepadViewInput { + func configure(with viewModel: NotepadViewModel) { + stateLabel.attributedText = viewModel.stateTitle + } + + func reloadData() { + DispatchQueue.main.async { [weak self] in + guard let self else { + return + } + + self.tableView.reloadData() + } + } +} diff --git a/Everyday/Modules/Notepad/NotepadViewController.swift b/Everyday/Modules/Notepad/NotepadViewController.swift deleted file mode 100644 index be7909f..0000000 --- a/Everyday/Modules/Notepad/NotepadViewController.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// NotepadViewController.swift -// Everyday -// -// Created by Михаил on 16.02.2024. -// -// - -import UIKit - -final class NotepadViewController: UIViewController { - private let output: NotepadViewOutput - - init(output: NotepadViewOutput) { - self.output = output - - super.init(nibName: nil, bundle: nil) - } - - @available(*, unavailable) - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = .green - } -} - -extension NotepadViewController: NotepadViewInput { -} diff --git a/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift b/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift new file mode 100644 index 0000000..798fe1c --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift @@ -0,0 +1,35 @@ +// +// ResultsViewModel.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit + +struct ResultsViewModel { + let title: NSAttributedString + let restTitle: NSAttributedString + let continueTitle: NSAttributedString + + init() { + let titleLabelTitle = "Результаты" + let titleLabelAttributedString = NSAttributedString(string: titleLabelTitle, attributes: Styles.titleAttributes) + let restButtonTitle = "Отдых" + let restButtonAttributedString = NSAttributedString(string: restButtonTitle, attributes: Styles.titleAttributes) + let continueButtonTitle = "Продолжить" + let continueButtonAttributedString = NSAttributedString(string: continueButtonTitle, attributes: Styles.titleAttributes) + + self.title = titleLabelAttributedString + self.restTitle = restButtonAttributedString + self.continueTitle = continueButtonAttributedString + } +} + +private extension ResultsViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsContainer.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsContainer.swift new file mode 100644 index 0000000..0052e12 --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsContainer.swift @@ -0,0 +1,42 @@ +// +// ResultsContainer.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class ResultsContainer { + let input: ResultsModuleInput + let viewController: UIViewController + private(set) weak var router: ResultsRouterInput! + + class func assemble(with context: ResultsContext) -> ResultsContainer { + let router = ResultsRouter() + let interactor = ResultsInteractor() + let presenter = ResultsPresenter(router: router, interactor: interactor, exercises: context.exercises) + let viewController = ResultsViewController(output: presenter) + + presenter.view = viewController + presenter.moduleOutput = context.moduleOutput + + interactor.output = presenter + + router.viewController = viewController + + return ResultsContainer(view: viewController, input: presenter, router: router) + } + + private init(view: UIViewController, input: ResultsModuleInput, router: ResultsRouterInput) { + self.viewController = view + self.input = input + self.router = router + } +} + +struct ResultsContext { + weak var moduleOutput: ResultsModuleOutput? + var exercises: [Exercise] +} diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsInteractor.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsInteractor.swift new file mode 100644 index 0000000..31f45a6 --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsInteractor.swift @@ -0,0 +1,16 @@ +// +// ResultsInteractor.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class ResultsInteractor { + weak var output: ResultsInteractorOutput? +} + +extension ResultsInteractor: ResultsInteractorInput { +} diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsPresenter.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsPresenter.swift new file mode 100644 index 0000000..4282a04 --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsPresenter.swift @@ -0,0 +1,60 @@ +// +// ResultsPresenter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class ResultsPresenter { + weak var view: ResultsViewInput? + weak var moduleOutput: ResultsModuleOutput? + + private let router: ResultsRouterInput + private let interactor: ResultsInteractorInput + + private var exercises: [Exercise] + + init(router: ResultsRouterInput, interactor: ResultsInteractorInput, exercises: [Exercise]) { + self.router = router + self.interactor = interactor + self.exercises = exercises + } +} + +extension ResultsPresenter: ResultsModuleInput { +} + +extension ResultsPresenter: ResultsViewOutput { + func didLoadView() { + let viewModel = ResultsViewModel() + view?.configure(with: viewModel) + } + + func numberOfRowsInSection(_ section: Int) -> Int { + exercises.count + } + + func getExercise(at index: Int) -> Exercise { + exercises[index] + } + + func didTapCloseButton() { + router.closeResults() + } + + func didTapRestButton() { + let timerContext = TimerContext() + router.openTimer(with: timerContext) + } + + func didTapContinueButton() { + moduleOutput?.changeSet(with: exercises) + router.closeResults() + } +} + +extension ResultsPresenter: ResultsInteractorOutput { +} diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsProtocols.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsProtocols.swift new file mode 100644 index 0000000..f468bcc --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsProtocols.swift @@ -0,0 +1,43 @@ +// +// ResultsProtocols.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +protocol ResultsModuleInput { + var moduleOutput: ResultsModuleOutput? { get } +} + +protocol ResultsModuleOutput: AnyObject { + func changeSet(with exercises: [Exercise]) +} + +protocol ResultsViewInput: AnyObject { + func configure(with viewModel: ResultsViewModel) + func reloadData() + func getSelf() -> ResultsViewController +} + +protocol ResultsViewOutput: AnyObject { + func didLoadView() + func numberOfRowsInSection(_ section: Int) -> Int + func getExercise(at index: Int) -> Exercise + func didTapCloseButton() + func didTapRestButton() + func didTapContinueButton() +} + +protocol ResultsInteractorInput: AnyObject { +} + +protocol ResultsInteractorOutput: AnyObject { +} + +protocol ResultsRouterInput: AnyObject { + func openTimer(with timerContext: TimerContext) + func closeResults() +} diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsRouter.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsRouter.swift new file mode 100644 index 0000000..bc23072 --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsRouter.swift @@ -0,0 +1,33 @@ +// +// ResultsRouter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class ResultsRouter { + weak var viewController: ResultsViewController? +} + +extension ResultsRouter: ResultsRouterInput { + func openTimer(with timerContext: TimerContext) { + guard let viewController = viewController else { + return + } + + let timerContainer = TimerContainer.assemble(with: timerContext) + let timerViewController = timerContainer.viewController + viewController.present(timerViewController, animated: true) + } + + func closeResults() { + guard let viewController = viewController else { + return + } + + viewController.dismiss(animated: true) + } +} diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift new file mode 100644 index 0000000..cabaac3 --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift @@ -0,0 +1,131 @@ +// +// ResultsTableViewCell.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit +import PinLayout + +class ResultsTableViewCell: UITableViewCell { + static let reuseID = "ResultsTableViewCell" + + // MARK: - Private properties + + private let exerciseNameLabel = UILabel() + private let minusButton = UIButton() + private let plusButton = UIButton() + private let resultTextField = UITextField() + + // MARK: - Init + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func layoutSubviews() { + super.layoutSubviews() + + layout() + } + + // MARK: - Interface + + func configure(with exercise: Exercise) { + exerciseNameLabel.text = exercise.name + resultTextField.text = exercise.result + } +} + +private extension ResultsTableViewCell { + + // MARK: - Layout + + func layout() { + exerciseNameLabel.pin + .left(20) + .vCenter() + .width(200) + .height(40) + + plusButton.pin + .vCenter() + .right(20) + .width(20) + .height(20) + + resultTextField.pin + .vCenter() + .before(of: plusButton) + .width(40) + .height(20) + + minusButton.pin + .vCenter() + .before(of: resultTextField) + .width(20) + .height(20) + } + + // MARK: - Setup + + func setup() { + setupMinusButton() + setupPlusButton() + setupResultTextField() + + contentView.addSubviews(exerciseNameLabel, plusButton, resultTextField, minusButton) + } + + func setupMinusButton() { + let minusButtonImage = UIImage(systemName: "minus") + minusButton.setImage(minusButtonImage, for: .normal) + minusButton.addTarget(self, action: #selector(didTapMinusButton), for: .touchUpInside) + } + + func setupPlusButton() { + let plusButtonImage = UIImage(systemName: "plus") + plusButton.setImage(plusButtonImage, for: .normal) + plusButton.addTarget(self, action: #selector(didTapPlusButton), for: .touchUpInside) + } + + func setupResultTextField() { + resultTextField.backgroundColor = .secondaryLabel + resultTextField.textAlignment = .center + } + + // MARK: - Actions + + @objc + func didTapMinusButton() { + guard + let resultText = resultTextField.text, + let result = Int(resultText) + else { + return + } + + resultTextField.text = String(result - 1) + } + + @objc + func didTapPlusButton() { + guard + let resultText = resultTextField.text, + let result = Int(resultText) + else { + return + } + + resultTextField.text = String(result + 1) + } +} diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift new file mode 100644 index 0000000..6401577 --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift @@ -0,0 +1,229 @@ +// +// ResultsViewController.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit +import PinLayout + +final class ResultsViewController: UIViewController { + + // MARK: - Private properties + + private let output: ResultsViewOutput + + private let backgroundView = UIView() + private let contentView = UIView() + private let closeButton = UIButton() + private let titleLabel = UILabel() + private let tableView = UITableView() + private let restButton = UIButton() + private let continueButton = UIButton() + + // MARK: - Init + + init(output: ResultsViewOutput) { + self.output = output + + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + output.didLoadView() + setup() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + layout() + } +} + +private extension ResultsViewController { + + // MARK: - Layout + + func layout() { + backgroundView.pin + .all() + + closeButton.pin + .top(8) + .right(8) + .width(40) + .height(40) + + titleLabel.pin + .top() + .height(80) + .left() + .right() + + restButton.pin + .bottom(20) + .height(40) + .left(40) + .width(100) + + continueButton.pin + .bottom(20) + .height(40) + .after(of: restButton) + .marginLeft(20) + .right(40) + + tableView.pin + .below(of: titleLabel) + .above(of: restButton) + .left() + .right() + } + + // MARK: - Setup + + func setup() { + setupView() + setupBackgroundView() + setupContentView() + setupTableView() + setupCloseButton() + setupTitleLabel() + setupRestButton() + setupContinueButton() + + contentView.addSubviews(tableView, closeButton, restButton, continueButton, titleLabel) + view.addSubviews(backgroundView, contentView) + } + + func setupView() { + view.backgroundColor = .clear + } + + func setupTableView() { + tableView.delegate = self + tableView.dataSource = self + tableView.register(ResultsTableViewCell.self, forCellReuseIdentifier: ResultsTableViewCell.reuseID) + } + + func setupBackgroundView() { + backgroundView.backgroundColor = .black.withAlphaComponent(0.5) + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapCloseButton)) + backgroundView.addGestureRecognizer(tapGesture) + } + + func setupContentView() { + contentView.backgroundColor = .white + + let width: CGFloat = view.bounds.width - 24 * 2 + let height: CGFloat = width + + let x = (view.bounds.width - width) / 2 + let y = (view.bounds.height - height) / 2 + + contentView.frame = CGRect(x: x, y: y, width: width, height: height) + contentView.layer.cornerRadius = 16 + } + + func setupCloseButton() { + closeButton.setTitle("", for: .normal) + let buttonImageConfiguration = UIImage.SymbolConfiguration(textStyle: .largeTitle) + let buttonImage = UIImage(systemName: "xmark.circle.fill", withConfiguration: buttonImageConfiguration) + closeButton.setImage(buttonImage, for: .normal) + closeButton.addTarget(self, action: #selector(didTapCloseButton), for: .touchUpInside) + closeButton.tintColor = .systemMint + } + + func setupRestButton() { + restButton.backgroundColor = .systemMint + restButton.layer.cornerRadius = 16 + restButton.addTarget(self, action: #selector(didTapRestButton), for: .touchUpInside) + } + + func setupContinueButton() { + continueButton.backgroundColor = .systemMint + continueButton.layer.cornerRadius = 16 + continueButton.addTarget(self, action: #selector(didTapContinueButton), for: .touchUpInside) + } + + func setupTitleLabel() { + titleLabel.textAlignment = .center + } + + // MARK: - Actions + + @objc + func didTapCloseButton() { + output.didTapCloseButton() + } + + @objc + func didTapRestButton() { + output.didTapRestButton() + } + + @objc + func didTapContinueButton() { + output.didTapContinueButton() + } +} + +// MARK: - UITableViewDataSource + +extension ResultsViewController: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + output.numberOfRowsInSection(section) + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: ResultsTableViewCell.reuseID, for: indexPath) as? ResultsTableViewCell else { + return UITableViewCell() + } + + let exercise = output.getExercise(at: indexPath.row) + cell.configure(with: exercise) + + return cell + } +} + +// MARK: - UITableViewDelegate + +extension ResultsViewController: UITableViewDelegate { +} + +// MARK: - ResultsViewInput + +extension ResultsViewController: ResultsViewInput { + func configure(with viewModel: ResultsViewModel) { + titleLabel.attributedText = viewModel.title + restButton.setAttributedTitle(viewModel.restTitle, for: .normal) + continueButton.setAttributedTitle(viewModel.continueTitle, for: .normal) + } + + func getSelf() -> ResultsViewController { + return self + } + + func reloadData() { + DispatchQueue.main.async { [weak self] in + guard let self else { + return + } + + self.tableView.reloadData() + } + } +} diff --git a/Everyday/Modules/Notepad/TimerScene/Models/TimerViewModel.swift b/Everyday/Modules/Notepad/TimerScene/Models/TimerViewModel.swift new file mode 100644 index 0000000..e4f6518 --- /dev/null +++ b/Everyday/Modules/Notepad/TimerScene/Models/TimerViewModel.swift @@ -0,0 +1,43 @@ +// +// TimerViewModel.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit + +struct TimerViewModel { + let remainingTimeTitle: NSAttributedString + let startTitle: NSAttributedString + let stopTitle: NSAttributedString + let resetTitle: NSAttributedString + let skipTitle: NSAttributedString + + init(remainingTime: Int) { + let remainingTimeLabelTitle = "\(remainingTime)" + let remainingTimeLabelAttributedString = NSAttributedString(string: remainingTimeLabelTitle, attributes: Styles.titleAttributes) + let startButtonTitle = "Старт" + let startButtonAttributedString = NSAttributedString(string: startButtonTitle, attributes: Styles.titleAttributes) + let stopButtonTitle = "Стоп" + let stopButtonAttributedString = NSAttributedString(string: stopButtonTitle, attributes: Styles.titleAttributes) + let resetButtonTitle = "Заново" + let resetButtonAttributedString = NSAttributedString(string: resetButtonTitle, attributes: Styles.titleAttributes) + let skipButtonTitle = "Пропустить" + let skipButtonAttributedString = NSAttributedString(string: skipButtonTitle, attributes: Styles.titleAttributes) + + self.remainingTimeTitle = remainingTimeLabelAttributedString + self.startTitle = startButtonAttributedString + self.stopTitle = stopButtonAttributedString + self.resetTitle = resetButtonAttributedString + self.skipTitle = skipButtonAttributedString + } +} + +private extension TimerViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/TimerScene/TimerContainer.swift b/Everyday/Modules/Notepad/TimerScene/TimerContainer.swift new file mode 100644 index 0000000..690ba2d --- /dev/null +++ b/Everyday/Modules/Notepad/TimerScene/TimerContainer.swift @@ -0,0 +1,41 @@ +// +// TimerContainer.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class TimerContainer { + let input: TimerModuleInput + let viewController: UIViewController + private(set) weak var router: TimerRouterInput! + + class func assemble(with context: TimerContext) -> TimerContainer { + let router = TimerRouter() + let interactor = TimerInteractor() + let presenter = TimerPresenter(router: router, interactor: interactor) + let viewController = TimerViewController(output: presenter) + + presenter.view = viewController + presenter.moduleOutput = context.moduleOutput + + interactor.output = presenter + + router.viewController = viewController + + return TimerContainer(view: viewController, input: presenter, router: router) + } + + private init(view: UIViewController, input: TimerModuleInput, router: TimerRouterInput) { + self.viewController = view + self.input = input + self.router = router + } +} + +struct TimerContext { + weak var moduleOutput: TimerModuleOutput? +} diff --git a/Everyday/Modules/Notepad/TimerScene/TimerInteractor.swift b/Everyday/Modules/Notepad/TimerScene/TimerInteractor.swift new file mode 100644 index 0000000..54da72d --- /dev/null +++ b/Everyday/Modules/Notepad/TimerScene/TimerInteractor.swift @@ -0,0 +1,16 @@ +// +// TimerInteractor.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class TimerInteractor { + weak var output: TimerInteractorOutput? +} + +extension TimerInteractor: TimerInteractorInput { +} diff --git a/Everyday/Modules/Notepad/TimerScene/TimerPresenter.swift b/Everyday/Modules/Notepad/TimerScene/TimerPresenter.swift new file mode 100644 index 0000000..cf5181e --- /dev/null +++ b/Everyday/Modules/Notepad/TimerScene/TimerPresenter.swift @@ -0,0 +1,72 @@ +// +// TimerPresenter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class TimerPresenter { + weak var view: TimerViewInput? + weak var moduleOutput: TimerModuleOutput? + + private let router: TimerRouterInput + private let interactor: TimerInteractorInput + + private var timer = Timer() + private var remainingTime: Int = 1 + + init(router: TimerRouterInput, interactor: TimerInteractorInput) { + self.router = router + self.interactor = interactor + } +} + +private extension TimerPresenter { + + // MARK: - Actions + + @objc + func step() { + if remainingTime > 0 { + remainingTime -= 1 + } else { + timer.invalidate() + } + + view?.updateRemainingTime(with: remainingTime) + } +} + +extension TimerPresenter: TimerModuleInput { +} + +extension TimerPresenter: TimerViewOutput { + func didLoadView() { + let viewModel = TimerViewModel(remainingTime: remainingTime) + view?.configure(with: viewModel) + } + + func didTapStartButton() { + timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(step), userInfo: nil, repeats: true) + } + + func didTapStopButton() { + timer.invalidate() + } + + func didTapResetButton() { + timer.invalidate() + remainingTime = 1 + view?.updateRemainingTime(with: remainingTime) + } + + func didTapSkipButton() { + router.closeTimer() + } +} + +extension TimerPresenter: TimerInteractorOutput { +} diff --git a/Everyday/Modules/Notepad/TimerScene/TimerProtocols.swift b/Everyday/Modules/Notepad/TimerScene/TimerProtocols.swift new file mode 100644 index 0000000..233b030 --- /dev/null +++ b/Everyday/Modules/Notepad/TimerScene/TimerProtocols.swift @@ -0,0 +1,39 @@ +// +// TimerProtocols.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +protocol TimerModuleInput { + var moduleOutput: TimerModuleOutput? { get } +} + +protocol TimerModuleOutput: AnyObject { +} + +protocol TimerViewInput: AnyObject { + func configure(with viewModel: TimerViewModel) + func updateRemainingTime(with time: Int) +} + +protocol TimerViewOutput: AnyObject { + func didLoadView() + func didTapStartButton() + func didTapStopButton() + func didTapResetButton() + func didTapSkipButton() +} + +protocol TimerInteractorInput: AnyObject { +} + +protocol TimerInteractorOutput: AnyObject { +} + +protocol TimerRouterInput: AnyObject { + func closeTimer() +} diff --git a/Everyday/Modules/Notepad/TimerScene/TimerRouter.swift b/Everyday/Modules/Notepad/TimerScene/TimerRouter.swift new file mode 100644 index 0000000..0a71ed7 --- /dev/null +++ b/Everyday/Modules/Notepad/TimerScene/TimerRouter.swift @@ -0,0 +1,23 @@ +// +// TimerRouter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class TimerRouter { + weak var viewController: TimerViewController? +} + +extension TimerRouter: TimerRouterInput { + func closeTimer() { + guard let viewController = viewController else { + return + } + + viewController.dismiss(animated: true) + } +} diff --git a/Everyday/Modules/Notepad/TimerScene/TimerViewController.swift b/Everyday/Modules/Notepad/TimerScene/TimerViewController.swift new file mode 100644 index 0000000..4afd558 --- /dev/null +++ b/Everyday/Modules/Notepad/TimerScene/TimerViewController.swift @@ -0,0 +1,166 @@ +// +// TimerViewController.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit +import PinLayout + +final class TimerViewController: UIViewController { + + // MARK: - Private properties + + private let output: TimerViewOutput + + private let remainingTimeLabel = UILabel() + private let startButton = UIButton() + private let stopButton = UIButton() + private let resetButton = UIButton() + private let skipButton = UIButton() + + // MARK: - Init + + init(output: TimerViewOutput) { + self.output = output + + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + output.didLoadView() + setup() + } + + override func viewDidLayoutSubviews() { + layout() + } +} + +private extension TimerViewController { + + // MARK: - Layout + + func layout() { + remainingTimeLabel.pin + .hCenter() + .top(200) + .width(200) + .height(40) + + startButton.pin + .below(of: remainingTimeLabel) + .hCenter() + .height(40) + .width(100) + + stopButton.pin + .below(of: startButton) + .hCenter() + .height(40) + .width(100) + + resetButton.pin + .below(of: stopButton) + .hCenter() + .height(40) + .width(100) + + skipButton.pin + .below(of: resetButton) + .hCenter() + .height(40) + .width(200) + } + + // MARK: - Setup + + func setup() { + setupView() + setupRemainingTimeLabel() + setupStartButton() + setupStopButton() + setupResetButton() + setupSkipButton() + + view.addSubviews(startButton, stopButton, resetButton, skipButton, remainingTimeLabel) + } + + func setupView() { + view.backgroundColor = .systemBackground + } + + func setupStartButton() { + startButton.backgroundColor = .systemMint + startButton.addTarget(self, action: #selector(didTapStartButton), for: .touchUpInside) + } + + func setupStopButton() { + stopButton.backgroundColor = .systemMint + stopButton.addTarget(self, action: #selector(didTapStopButton), for: .touchUpInside) + } + + func setupResetButton() { + resetButton.backgroundColor = .systemMint + resetButton.addTarget(self, action: #selector(didTapResetButton), for: .touchUpInside) + } + + func setupSkipButton() { + skipButton.backgroundColor = .systemMint + skipButton.addTarget(self, action: #selector(didTapSkipButton), for: .touchUpInside) + } + + func setupRemainingTimeLabel() { + remainingTimeLabel.font = UIFont.systemFont(ofSize: 24, weight: .bold) + remainingTimeLabel.textAlignment = .center + } + + // MARK: - Actions + + @objc + func didTapStartButton() { + output.didTapStartButton() + } + + @objc + func didTapStopButton() { + output.didTapStopButton() + } + + @objc + func didTapResetButton() { + output.didTapResetButton() + } + + @objc + func didTapSkipButton() { + output.didTapSkipButton() + } +} + +// MARK: - TimerViewInput + +extension TimerViewController: TimerViewInput { + func configure(with viewModel: TimerViewModel) { + remainingTimeLabel.attributedText = viewModel.remainingTimeTitle + startButton.setAttributedTitle(viewModel.startTitle, for: .normal) + stopButton.setAttributedTitle(viewModel.stopTitle, for: .normal) + resetButton.setAttributedTitle(viewModel.resetTitle, for: .normal) + skipButton.setAttributedTitle(viewModel.skipTitle, for: .normal) + } + + func updateRemainingTime(with time: Int) { + remainingTimeLabel.text = String(time) + } +} diff --git a/Everyday/Modules/Notepad/TrainingScene/Models/TrainingViewModel.swift b/Everyday/Modules/Notepad/TrainingScene/Models/TrainingViewModel.swift new file mode 100644 index 0000000..ae8c88b --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/Models/TrainingViewModel.swift @@ -0,0 +1,27 @@ +// +// TrainingViewModel.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit + +struct TrainingViewModel { + let finishTitle: NSAttributedString + + init() { + let finishButtonTitle = "Закончить" + let finishButtonAttributedString = NSAttributedString(string: finishButtonTitle, attributes: Styles.titleAttributes) + + self.finishTitle = finishButtonAttributedString + } +} + +private extension TrainingViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingContainer.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingContainer.swift new file mode 100644 index 0000000..2d6c2f6 --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingContainer.swift @@ -0,0 +1,42 @@ +// +// TrainingContainer.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class TrainingContainer { + let input: TrainingModuleInput + let viewController: UIViewController + private(set) weak var router: TrainingRouterInput! + + class func assemble(with context: TrainingContext) -> TrainingContainer { + let router = TrainingRouter() + let interactor = TrainingInteractor() + let presenter = TrainingPresenter(router: router, interactor: interactor, workoutDay: context.workoutDay) + let viewController = TrainingViewController(output: presenter) + + presenter.view = viewController + presenter.moduleOutput = context.moduleOutput + + interactor.output = presenter + + router.viewController = viewController + + return TrainingContainer(view: viewController, input: presenter, router: router) + } + + private init(view: UIViewController, input: TrainingModuleInput, router: TrainingRouterInput) { + self.viewController = view + self.input = input + self.router = router + } +} + +struct TrainingContext { + weak var moduleOutput: TrainingModuleOutput? + let workoutDay: (workout: Workout, indexOfDay: Int) +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingInteractor.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingInteractor.swift new file mode 100644 index 0000000..7d5b4e2 --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingInteractor.swift @@ -0,0 +1,16 @@ +// +// TrainingInteractor.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class TrainingInteractor { + weak var output: TrainingInteractorOutput? +} + +extension TrainingInteractor: TrainingInteractorInput { +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift new file mode 100644 index 0000000..c0a0683 --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift @@ -0,0 +1,111 @@ +// +// TrainingPresenter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +final class TrainingPresenter { + weak var view: TrainingViewInput? + weak var moduleOutput: TrainingModuleOutput? + + private let router: TrainingRouterInput + private let interactor: TrainingInteractorInput + + private var workoutDay: (workout: Workout, indexOfDay: Int) + private var indexOfSet: Int = 0 + private var switchStates: [Bool] = [] + + init(router: TrainingRouterInput, interactor: TrainingInteractorInput, workoutDay: (workout: Workout, indexOfDay: Int)) { + self.router = router + self.interactor = interactor + self.workoutDay = workoutDay + } +} + +extension TrainingPresenter: TrainingModuleInput { +} + +extension TrainingPresenter: TrainingViewOutput { + func didLoadView() { + let viewModel = TrainingViewModel() + view?.configure(with: viewModel) + switchStates = [Bool](repeating: false, count: workoutDay.workout.days[workoutDay.indexOfDay].sets[0].exercises.count) + view?.reloadData() + } + + func numberOfRowsInSection(_ section: Int) -> Int { + workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises.count + } + + func getExercise(at index: Int) -> Exercise { + workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises[index] + } + + func setSwitchState(at index: Int, with value: Bool) { + switchStates[index] = value + let allSatisfy = switchStates.allSatisfy{ $0 } + if allSatisfy { + view?.showFinishButton() + } else { + view?.hideFinishButton() + } + } + + func getSwitchState(at index: Int) -> Bool { + switchStates[index] + } + + func didSelectRowAt(index: Int) { + if !switchStates[index] { + let exercise = workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises[index] + let exerciseContext = ExerciseContext(moduleOutput: self, exercise: exercise, indexOfSet: indexOfSet) + router.openExercise(with: exerciseContext) + } + } + + func didTapStartButton(number: Int) { + let exercise = workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises[number] + let exerciseContext = ExerciseContext(moduleOutput: self, exercise: exercise, indexOfSet: indexOfSet) + router.openExercise(with: exerciseContext) + } + + func didTapFinishButton() { + let exercises = workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises + let resultsContext = ResultsContext(moduleOutput: self, exercises: exercises) + router.showResults(with: resultsContext) + } +} + +extension TrainingPresenter: ExerciseModuleOutput { + func setResult(of exercise: String, with result: String, at indexOfSet: Int) { + guard let exerciseNumber1 = self.workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises.firstIndex(where: { $0.name == exercise }) else { + return + } + + self.workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises[exerciseNumber1].result = result + view?.reloadData() + } +} + +extension TrainingPresenter: ResultsModuleOutput { + func changeSet(with exercises: [Exercise]) { + let index = workoutDay.workout.days[workoutDay.indexOfDay].sets.firstIndex { $0.exercises[0].name == exercises[0].name }! + if workoutDay.workout.days[workoutDay.indexOfDay].sets.count > index + 1 { + self.indexOfSet = index + 1 + } else { + router.openExtra() + return + } + + switchStates = [Bool](repeating: false, count: workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises.count) + view?.hideFinishButton() + view?.reloadData() + } +} + +extension TrainingPresenter: TrainingInteractorOutput { +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingProtocols.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingProtocols.swift new file mode 100644 index 0000000..bece0e2 --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingProtocols.swift @@ -0,0 +1,46 @@ +// +// TrainingProtocols.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import Foundation + +protocol TrainingModuleInput { + var moduleOutput: TrainingModuleOutput? { get } +} + +protocol TrainingModuleOutput: AnyObject { +} + +protocol TrainingViewInput: AnyObject { + func configure(with viewModel: TrainingViewModel) + func reloadData() + func showFinishButton() + func hideFinishButton() +} + +protocol TrainingViewOutput: AnyObject { + func didLoadView() + func numberOfRowsInSection(_ section: Int) -> Int + func getExercise(at index: Int) -> Exercise + func setSwitchState(at index: Int, with value: Bool) + func getSwitchState(at index: Int) -> Bool + func didSelectRowAt(index: Int) + func didTapStartButton(number: Int) + func didTapFinishButton() +} + +protocol TrainingInteractorInput: AnyObject { +} + +protocol TrainingInteractorOutput: AnyObject { +} + +protocol TrainingRouterInput: AnyObject { + func openExercise(with exerciseContext: ExerciseContext) + func showResults(with resultsContext: ResultsContext) + func openExtra() +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift new file mode 100644 index 0000000..45f77e3 --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift @@ -0,0 +1,50 @@ +// +// TrainingRouter.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit + +final class TrainingRouter { + weak var viewController: TrainingViewController? +} + +extension TrainingRouter: TrainingRouterInput { + func openExercise(with exerciseContext: ExerciseContext) { + guard + let viewController = viewController, + let navigationController = viewController.navigationController + else { + return + } + + let exerciseContainer = ExerciseContainer.assemble(with: exerciseContext) + navigationController.pushViewController(exerciseContainer.viewController, animated: true) + } + + func showResults(with resultsContext: ResultsContext) { + guard let viewController = viewController else { + return + } + + let resultsContainer = ResultsContainer.assemble(with: resultsContext) + let resultsViewController = resultsContainer.viewController + resultsViewController.modalPresentationStyle = .overFullScreen + viewController.present(resultsViewController, animated: false) + } + + func openExtra() { + guard + let viewController = viewController, + let navigationController = viewController.navigationController + else { + return + } + + let extraContainer = ExtraContainer.assemble(with: .init()) + navigationController.pushViewController(extraContainer.viewController, animated: true) + } +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift new file mode 100644 index 0000000..c5f8597 --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift @@ -0,0 +1,158 @@ +// +// TrainingTableViewCell.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import UIKit +import PinLayout +import M13Checkbox + +// MARK: - Protocols + +protocol SwitchTableViewCellDelegate: AnyObject { + func switchCell(_ cell: TrainingTableViewCell, with value: Bool) +} + +class TrainingTableViewCell: UITableViewCell { + static let reuseID = "TrainingTableViewCell" + + // MARK: - Private properties + + private let checkbox = M13Checkbox() + private let exerciseNameLabel = UILabel() + private let resultLabel = UILabel() + private let startButton = UIButton() + + // MARK: - Public properties + + weak var delegate: SwitchTableViewCellDelegate? + + // MARK: - Init + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func layoutSubviews() { + layout() + } + + // MARK: - Interface + + func configure(with exercise: Exercise, and index: Int) { + exerciseNameLabel.text = exercise.name + resultLabel.text = exercise.result + startButton.tag = index + } + + func updateResult(with result: String) { + resultLabel.text = result + } + + func showStartButton() { + startButton.isHidden = false + } + + func hideStartButton() { + startButton.isHidden = true + } + + func addStartButtonTarget(_ target: Any?, action: Selector) { + startButton.addTarget(target, action: action, for: .touchUpInside) + } + + func setStartButtonTag(_ tag: Int) { + startButton.tag = tag + } + + func disableCheckBox() { + checkbox.isUserInteractionEnabled = false + } + + func enableCheckBox() { + checkbox.isUserInteractionEnabled = true + } + + func uncheckCheckBox() { + checkbox.setCheckState(.unchecked, animated: true) + } + + func checkCheckBox() { + checkbox.setCheckState(.checked, animated: true) + } +} + +private extension TrainingTableViewCell { + + // MARK: - Layout + + func layout() { + checkbox.pin + .left(20) + .vCenter() + .width(40) + .height(40) + + exerciseNameLabel.pin + .after(of: checkbox) + .marginLeft(20) + .width(200) + .height(40) + .vCenter() + + resultLabel.pin + .right() + .after(of: exerciseNameLabel) + .marginLeft(20) + .height(40) + .vCenter() + + startButton.pin + .right(20) + .after(of: exerciseNameLabel) + .marginLeft(20) + .height(40) + .vCenter() + } + + // MARK: - Setup + + func setup() { + checkbox.addTarget(self, action: #selector(switchValueChanged), for: .valueChanged) + checkbox.stateChangeAnimation = .bounce(.fill) + checkbox.setCheckState(.unchecked, animated: true) + + startButton.setTitle("Начать", for: .normal) + startButton.backgroundColor = .systemMint + startButton.layer.cornerRadius = 16 + startButton.isHidden = true + + contentView.addSubviews(checkbox, exerciseNameLabel, resultLabel, startButton) + } + + // MARK: - Actions + + @objc + func switchValueChanged(_ sender: M13Checkbox) { + var value = false + switch sender.checkState { + case .unchecked: + value = false + case .checked: + value = true + case .mixed: + value = false + } + delegate?.switchCell(self, with: value) + } +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift new file mode 100644 index 0000000..2b5c308 --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift @@ -0,0 +1,175 @@ +// +// TrainingViewController.swift +// Everyday +// +// Created by user on 28.02.2024. +// +// + +import UIKit +import PinLayout + +final class TrainingViewController: UIViewController { + + // MARK: - Private properties + + private let output: TrainingViewOutput + + private let finishButton = UIButton() + private let tableView = UITableView() + + // MARK: - Init + + init(output: TrainingViewOutput) { + self.output = output + + super.init(nibName: nil, bundle: nil) + } + + @available(*, unavailable) + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + output.didLoadView() + setup() + } + + override func viewDidLayoutSubviews() { + layout() + } +} + +private extension TrainingViewController { + // MARK: - Layout + + func layout() { + finishButton.pin + .top(view.pin.safeArea) + .marginTop(40) + .horizontally(20) + .height(30) + + tableView.pin + .below(of: finishButton) + .marginTop(170) + .horizontally() + .bottom() + } + + // MARK: - Setup + + func setup() { + setupView() + setupFinishButton() + setupTableView() + + view.addSubviews(finishButton, tableView) + } + + func setupView() { + view.backgroundColor = .systemBackground + } + + func setupTableView() { + tableView.delegate = self + tableView.dataSource = self + tableView.register(TrainingTableViewCell.self, forCellReuseIdentifier: TrainingTableViewCell.reuseID) + tableView.rowHeight = 80 + } + + func setupFinishButton() { + finishButton.backgroundColor = .systemMint + finishButton.addTarget(self, action: #selector(didTapFinishButton), for: .touchUpInside) + finishButton.isHidden = true + } + + // MARK: - Actions + + @objc + func didTapStartButton(_ button: UIButton) { + output.didTapStartButton(number: button.tag) + } + + @objc + func didTapFinishButton() { + output.didTapFinishButton() + } +} + +// MARK: - UITableViewDataSource + +extension TrainingViewController: UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + output.numberOfRowsInSection(section) + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: TrainingTableViewCell.reuseID, for: indexPath) as? TrainingTableViewCell else { + return UITableViewCell() + } + + cell.configure(with: output.getExercise(at: indexPath.row), and: indexPath.row) + cell.addStartButtonTarget(self, action: #selector(didTapStartButton)) + cell.delegate = self + + if output.getSwitchState(at: indexPath.row) { + cell.checkCheckBox() + } else { + cell.uncheckCheckBox() + } + + return cell + } +} + +// MARK: - UITableViewDelegate + +extension TrainingViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + output.didSelectRowAt(index: indexPath.row) + } +} + +// MARK: - SwitchTableViewCellDelegate + +extension TrainingViewController: SwitchTableViewCellDelegate { + func switchCell(_ cell: TrainingTableViewCell, with value: Bool) { + guard let indexPath = tableView.indexPath(for: cell) else { + return + } + + output.setSwitchState(at: indexPath.row, with: value) + } +} + +// MARK: - TrainingViewInput + +extension TrainingViewController: TrainingViewInput { + func configure(with viewModel: TrainingViewModel) { + finishButton.setAttributedTitle(viewModel.finishTitle, for: .normal) + } + + func showFinishButton() { + finishButton.isHidden = false + } + + func hideFinishButton() { + finishButton.isHidden = true + } + + func reloadData() { + DispatchQueue.main.async { [weak self] in + guard let self else { + return + } + + self.tableView.reloadData() + } + } +} diff --git a/Everyday/Services/Day/DayService.swift b/Everyday/Services/Day/DayService.swift new file mode 100644 index 0000000..e11a3bc --- /dev/null +++ b/Everyday/Services/Day/DayService.swift @@ -0,0 +1,36 @@ +// +// DayService.swift +// Everyday +// +// Created by user on 28.02.2024. +// + +import Foundation + +protocol DayServiceDescription { + func getDaySchedule(completion: @escaping (Result<[(workout: Workout, indexOfDay: Int)], CustomError>) -> Void) + func getDayResults(on date: Date, completion: @escaping (Result<[(workout: Workout, indexOfDay: Int)], CustomError>) -> Void) +} + +final class DayService: DayServiceDescription { + static let shared: DayServiceDescription = DayService() + + private init() {} + + func getDaySchedule(completion: @escaping (Result<[(workout: Workout, indexOfDay: Int)], CustomError>) -> Void) { + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + let workoutDays = MockSchedule.mockSchedule.daysOfWeek[4] + let result: Result<[(workout: Workout, indexOfDay: Int)], CustomError> = .success(workoutDays) // .failure(.unknownError) + completion(result) + } + } + + func getDayResults(on date: Date, completion: @escaping (Result<[(workout: Workout, indexOfDay: Int)], CustomError>) -> Void) { + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + let workoutDays = MockSchedule.mockSchedule.daysOfWeek[4] +// let result: Result<[(workout: Workout, indexOfDay: Int)], CustomError> = .success(workoutDays) + let result: Result<[(workout: Workout, indexOfDay: Int)], CustomError> = .failure(.unknownError) + completion(result) + } + } +} From 9b8237376ccb1e79b8043ea6baa69780fb7cecf9 Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Thu, 29 Feb 2024 22:40:20 +0300 Subject: [PATCH 02/13] hotfix --- Everyday/Entities/User.swift | 5 ----- .../Modules/Notepad/NotepadScene/NotepadInteractor.swift | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Everyday/Entities/User.swift b/Everyday/Entities/User.swift index 8964021..e23bdae 100644 --- a/Everyday/Entities/User.swift +++ b/Everyday/Entities/User.swift @@ -7,11 +7,6 @@ import Foundation -struct User { - let info: String // change for several properies: name, weight, etc. - let schedule: Schedule -} - struct Schedule { let daysOfWeek: [[(workout: Workout, indexOfDay: Int)]] // 7 elements (arrays) = 7 days } diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift index 13f4b9d..60bf666 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift @@ -10,9 +10,9 @@ import Foundation final class NotepadInteractor { weak var output: NotepadInteractorOutput? - private let dayManager: DayManagerDescription + private let dayManager: DayServiceDescription - init(dayManager: DayManagerDescription = DayManager.shared) { + init(dayManager: DayServiceDescription = DayService.shared) { self.dayManager = dayManager } } From 3f1a006fdb3fdf73cfaa37fd4bfc68f99c26ebce Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Fri, 1 Mar 2024 08:56:41 +0300 Subject: [PATCH 03/13] comment vk + groups --- Everyday.xcodeproj/project.pbxproj | 189 ++++++------------ .../xcshareddata/swiftpm/Package.resolved | 69 +++---- .../ProfileSetup/ProfileSetupView.swift | 63 +++--- .../SignUp/SignUpInteractor.swift | 20 +- .../SignUp/SignUpPresenter.swift | 20 +- .../SignUp/SignUpProtocols.swift | 2 +- Everyday/Services/Auth/AuthService.swift | 19 +- .../Auth/VKIDAuth/VKIDAuthService.swift | 122 +++++------ Everyday/Support/AppDelegate.swift | 6 +- Everyday/Support/SceneDelegate.swift | 2 +- 10 files changed, 216 insertions(+), 296 deletions(-) diff --git a/Everyday.xcodeproj/project.pbxproj b/Everyday.xcodeproj/project.pbxproj index 4a72299..5687119 100644 --- a/Everyday.xcodeproj/project.pbxproj +++ b/Everyday.xcodeproj/project.pbxproj @@ -7,16 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 9E2A8BB22B84F106004A81CF /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BB12B84F106004A81CF /* FirebaseAppCheck */; }; - 9E2A8BB42B84F106004A81CF /* FirebaseAppDistribution-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BB32B84F106004A81CF /* FirebaseAppDistribution-Beta */; }; - 9E2A8BB62B84F106004A81CF /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BB52B84F106004A81CF /* FirebaseAuth */; }; - 9E2A8BB82B84F106004A81CF /* FirebaseAuthCombine-Community in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BB72B84F106004A81CF /* FirebaseAuthCombine-Community */; }; - 9E2A8BBA2B84F106004A81CF /* FirebaseDynamicLinks in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BB92B84F106004A81CF /* FirebaseDynamicLinks */; }; - 9E2A8BBC2B84F106004A81CF /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BBB2B84F106004A81CF /* FirebaseFirestore */; }; - 9E2A8BBE2B84F106004A81CF /* FirebaseFirestoreCombine-Community in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BBD2B84F106004A81CF /* FirebaseFirestoreCombine-Community */; }; - 9E2A8BC02B84F106004A81CF /* FirebaseFirestoreSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BBF2B84F106004A81CF /* FirebaseFirestoreSwift */; }; - 9E2A8BC22B84F106004A81CF /* FirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BC12B84F106004A81CF /* FirebaseStorage */; }; - 9E2A8BC42B84F106004A81CF /* FirebaseStorageCombine-Community in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2A8BC32B84F106004A81CF /* FirebaseStorageCombine-Community */; }; 9E2A8BC62B84FEDD004A81CF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9E2A8BC52B84FEDD004A81CF /* GoogleService-Info.plist */; }; 9E2A8BC92B850461004A81CF /* FIrebaseAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2A8BC82B850461004A81CF /* FIrebaseAuthService.swift */; }; 9E2A8BCD2B8520B2004A81CF /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2A8BCC2B8520B2004A81CF /* AlertManager.swift */; }; @@ -26,8 +16,6 @@ 9E4382D42B83738800C69708 /* VKIDAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4382CF2B83738800C69708 /* VKIDAuthService.swift */; }; 9E4382D52B83738800C69708 /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4382D02B83738800C69708 /* AuthService.swift */; }; 9E4382D62B83738800C69708 /* GoogleAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4382D22B83738800C69708 /* GoogleAuthService.swift */; }; - 9E4382D92B83746B00C69708 /* GoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = 9E4382D82B83746B00C69708 /* GoogleSignIn */; }; - 9E4382DB2B83746B00C69708 /* GoogleSignInSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 9E4382DA2B83746B00C69708 /* GoogleSignInSwift */; }; 9E53FB342B7F87BA00C55A45 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E53FB332B7F87BA00C55A45 /* AppDelegate.swift */; }; 9E53FB362B7F87BA00C55A45 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E53FB352B7F87BA00C55A45 /* SceneDelegate.swift */; }; 9E53FB3B2B7F87BA00C55A45 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9E53FB392B7F87BA00C55A45 /* Main.storyboard */; }; @@ -36,7 +24,6 @@ 9E53FB4E2B7F950B00C55A45 /* Color+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E53FB4D2B7F950B00C55A45 /* Color+Extension.swift */; }; 9E53FB502B7F951000C55A45 /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E53FB4F2B7F951000C55A45 /* UIColor+Extension.swift */; }; 9E53FB522B7F951400C55A45 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E53FB512B7F951400C55A45 /* String+Extension.swift */; }; - 9E5B74CC2B7F963100E2BDE6 /* PinLayout in Frameworks */ = {isa = PBXBuildFile; productRef = 9E5B74CB2B7F963100E2BDE6 /* PinLayout */; }; 9E5B74CE2B7F966100E2BDE6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9E5B74CD2B7F966100E2BDE6 /* Assets.xcassets */; }; 9E5B74E92B7F99FB00E2BDE6 /* WelcomeScreenContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5B74E12B7F99FB00E2BDE6 /* WelcomeScreenContainer.swift */; }; 9E5B74EA2B7F99FB00E2BDE6 /* WelcomeScreenRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5B74E22B7F99FB00E2BDE6 /* WelcomeScreenRouter.swift */; }; @@ -84,8 +71,6 @@ 9E5B754B2B7F9D7600E2BDE6 /* ProfileSetupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5B75352B7F9D7600E2BDE6 /* ProfileSetupViewModel.swift */; }; 9E5B754C2B7F9D7600E2BDE6 /* ProfileSetupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5B75362B7F9D7600E2BDE6 /* ProfileSetupModel.swift */; }; 9E5B754D2B7F9D7600E2BDE6 /* ProfileSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5B75372B7F9D7600E2BDE6 /* ProfileSetupView.swift */; }; - 9E673DA62B8275680041B97D /* VKID in Frameworks */ = {isa = PBXBuildFile; productRef = 9E673DA52B8275680041B97D /* VKID */; }; - 9E673DA82B8275680041B97D /* VKIDCore in Frameworks */ = {isa = PBXBuildFile; productRef = 9E673DA72B8275680041B97D /* VKIDCore */; }; 9E7C19972B8BF1340006D48C /* PasswordGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7C19962B8BF1340006D48C /* PasswordGenerator.swift */; }; 9E7C19992B8CC3E80006D48C /* NameGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7C19982B8CC3E80006D48C /* NameGenerator.swift */; }; 9EE8AE052B7FA45F001D126F /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9EE8AE042B7FA45F001D126F /* Localizable.xcstrings */; }; @@ -114,6 +99,13 @@ 9EE8AE392B7FB96E001D126F /* WorkoutProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE8AE332B7FB96E001D126F /* WorkoutProtocols.swift */; }; 9EE8AE3A2B7FB96E001D126F /* WorkoutInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE8AE342B7FB96E001D126F /* WorkoutInteractor.swift */; }; 9EE8AE3B2B7FB96E001D126F /* WorkoutContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE8AE352B7FB96E001D126F /* WorkoutContainer.swift */; }; + CE5E73672B9124C2007620A7 /* GoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73662B9124C2007620A7 /* GoogleSignIn */; }; + CE5E73692B9124C2007620A7 /* GoogleSignInSwift in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73682B9124C2007620A7 /* GoogleSignInSwift */; }; + CE5E736C2B912559007620A7 /* PinLayout in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E736B2B912559007620A7 /* PinLayout */; }; + CE5E736F2B9129C9007620A7 /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E736E2B9129C9007620A7 /* FirebaseAppCheck */; }; + CE5E73712B9129C9007620A7 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73702B9129C9007620A7 /* FirebaseAuth */; }; + CE5E73732B9129C9007620A7 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73722B9129C9007620A7 /* FirebaseFirestore */; }; + CE5E73762B912DA1007620A7 /* M13Checkbox in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73752B912DA1007620A7 /* M13Checkbox */; }; CEED457A2B8F693E00DD4058 /* CustomError.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45792B8F693E00DD4058 /* CustomError.swift */; }; CEED457D2B8F69C500DD4058 /* DayService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED457C2B8F69C500DD4058 /* DayService.swift */; }; CEED45802B8F6A7B00DD4058 /* Workout.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED457F2B8F6A7B00DD4058 /* Workout.swift */; }; @@ -310,21 +302,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9E2A8BBE2B84F106004A81CF /* FirebaseFirestoreCombine-Community in Frameworks */, - 9E4382DB2B83746B00C69708 /* GoogleSignInSwift in Frameworks */, - 9E2A8BBA2B84F106004A81CF /* FirebaseDynamicLinks in Frameworks */, - 9E2A8BC02B84F106004A81CF /* FirebaseFirestoreSwift in Frameworks */, - 9E673DA62B8275680041B97D /* VKID in Frameworks */, - 9E4382D92B83746B00C69708 /* GoogleSignIn in Frameworks */, - 9E2A8BBC2B84F106004A81CF /* FirebaseFirestore in Frameworks */, - 9E2A8BC22B84F106004A81CF /* FirebaseStorage in Frameworks */, - 9E2A8BB62B84F106004A81CF /* FirebaseAuth in Frameworks */, - 9E2A8BC42B84F106004A81CF /* FirebaseStorageCombine-Community in Frameworks */, - 9E2A8BB22B84F106004A81CF /* FirebaseAppCheck in Frameworks */, - 9E673DA82B8275680041B97D /* VKIDCore in Frameworks */, - 9E5B74CC2B7F963100E2BDE6 /* PinLayout in Frameworks */, - 9E2A8BB42B84F106004A81CF /* FirebaseAppDistribution-Beta in Frameworks */, - 9E2A8BB82B84F106004A81CF /* FirebaseAuthCombine-Community in Frameworks */, + CE5E73762B912DA1007620A7 /* M13Checkbox in Frameworks */, + CE5E736F2B9129C9007620A7 /* FirebaseAppCheck in Frameworks */, + CE5E73712B9129C9007620A7 /* FirebaseAuth in Frameworks */, + CE5E736C2B912559007620A7 /* PinLayout in Frameworks */, + CE5E73692B9124C2007620A7 /* GoogleSignInSwift in Frameworks */, + CE5E73672B9124C2007620A7 /* GoogleSignIn in Frameworks */, + CE5E73732B9129C9007620A7 /* FirebaseFirestore in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -885,21 +869,13 @@ ); name = Everyday; packageProductDependencies = ( - 9E5B74CB2B7F963100E2BDE6 /* PinLayout */, - 9E673DA52B8275680041B97D /* VKID */, - 9E673DA72B8275680041B97D /* VKIDCore */, - 9E4382D82B83746B00C69708 /* GoogleSignIn */, - 9E4382DA2B83746B00C69708 /* GoogleSignInSwift */, - 9E2A8BB12B84F106004A81CF /* FirebaseAppCheck */, - 9E2A8BB32B84F106004A81CF /* FirebaseAppDistribution-Beta */, - 9E2A8BB52B84F106004A81CF /* FirebaseAuth */, - 9E2A8BB72B84F106004A81CF /* FirebaseAuthCombine-Community */, - 9E2A8BB92B84F106004A81CF /* FirebaseDynamicLinks */, - 9E2A8BBB2B84F106004A81CF /* FirebaseFirestore */, - 9E2A8BBD2B84F106004A81CF /* FirebaseFirestoreCombine-Community */, - 9E2A8BBF2B84F106004A81CF /* FirebaseFirestoreSwift */, - 9E2A8BC12B84F106004A81CF /* FirebaseStorage */, - 9E2A8BC32B84F106004A81CF /* FirebaseStorageCombine-Community */, + CE5E73662B9124C2007620A7 /* GoogleSignIn */, + CE5E73682B9124C2007620A7 /* GoogleSignInSwift */, + CE5E736B2B912559007620A7 /* PinLayout */, + CE5E736E2B9129C9007620A7 /* FirebaseAppCheck */, + CE5E73702B9129C9007620A7 /* FirebaseAuth */, + CE5E73722B9129C9007620A7 /* FirebaseFirestore */, + CE5E73752B912DA1007620A7 /* M13Checkbox */, ); productName = Everyday; productReference = 9E53FB302B7F87BA00C55A45 /* Everyday.app */; @@ -930,11 +906,10 @@ ); mainGroup = 9E53FB272B7F87BA00C55A45; packageReferences = ( - 9E5B74CA2B7F963100E2BDE6 /* XCRemoteSwiftPackageReference "PinLayout" */, - 9E673DA42B8275680041B97D /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */, - 9E4382D72B83746B00C69708 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */, - 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, - CEED459D2B8F6EB100DD4058 /* XCRemoteSwiftPackageReference "M13Checkbox" */, + CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */, + CE5E736A2B912559007620A7 /* XCRemoteSwiftPackageReference "PinLayout" */, + CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + CE5E73742B912DA1007620A7 /* XCRemoteSwiftPackageReference "M13Checkbox" */, ); productRefGroup = 9E53FB312B7F87BA00C55A45 /* Products */; projectDirPath = ""; @@ -1199,7 +1174,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.6; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -1257,7 +1232,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.6; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -1274,7 +1249,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 72F47Y7J7T; + DEVELOPMENT_TEAM = LW5X22QCW4; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Everyday/Info.plist; @@ -1283,7 +1258,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 16.6; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1304,7 +1279,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 72F47Y7J7T; + DEVELOPMENT_TEAM = LW5X22QCW4; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Everyday/Info.plist; @@ -1313,7 +1288,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 16.6; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1351,15 +1326,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 10.21.0; - }; - }; - 9E4382D72B83746B00C69708 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = { + CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/google/GoogleSignIn-iOS"; requirement = { @@ -1367,23 +1334,23 @@ minimumVersion = 7.0.0; }; }; - 9E5B74CA2B7F963100E2BDE6 /* XCRemoteSwiftPackageReference "PinLayout" */ = { + CE5E736A2B912559007620A7 /* XCRemoteSwiftPackageReference "PinLayout" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/layoutBox/PinLayout"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.10.5; + minimumVersion = 1.0.0; }; }; - 9E673DA42B8275680041B97D /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */ = { + CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/VKCOM/vkid-ios-sdk.git"; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.2.2; + minimumVersion = 9.0.0; }; }; - CEED459D2B8F6EB100DD4058 /* XCRemoteSwiftPackageReference "M13Checkbox" */ = { + CE5E73742B912DA1007620A7 /* XCRemoteSwiftPackageReference "M13Checkbox" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/Marxon13/M13Checkbox"; requirement = { @@ -1394,80 +1361,40 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 9E2A8BB12B84F106004A81CF /* FirebaseAppCheck */ = { + CE5E73662B9124C2007620A7 /* GoogleSignIn */ = { isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseAppCheck; + package = CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; + productName = GoogleSignIn; }; - 9E2A8BB32B84F106004A81CF /* FirebaseAppDistribution-Beta */ = { + CE5E73682B9124C2007620A7 /* GoogleSignInSwift */ = { isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseAppDistribution-Beta"; + package = CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; + productName = GoogleSignInSwift; }; - 9E2A8BB52B84F106004A81CF /* FirebaseAuth */ = { + CE5E736B2B912559007620A7 /* PinLayout */ = { isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseAuth; + package = CE5E736A2B912559007620A7 /* XCRemoteSwiftPackageReference "PinLayout" */; + productName = PinLayout; }; - 9E2A8BB72B84F106004A81CF /* FirebaseAuthCombine-Community */ = { + CE5E736E2B9129C9007620A7 /* FirebaseAppCheck */ = { isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseAuthCombine-Community"; + package = CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAppCheck; }; - 9E2A8BB92B84F106004A81CF /* FirebaseDynamicLinks */ = { + CE5E73702B9129C9007620A7 /* FirebaseAuth */ = { isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseDynamicLinks; + package = CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAuth; }; - 9E2A8BBB2B84F106004A81CF /* FirebaseFirestore */ = { + CE5E73722B9129C9007620A7 /* FirebaseFirestore */ = { isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + package = CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseFirestore; }; - 9E2A8BBD2B84F106004A81CF /* FirebaseFirestoreCombine-Community */ = { - isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseFirestoreCombine-Community"; - }; - 9E2A8BBF2B84F106004A81CF /* FirebaseFirestoreSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseFirestoreSwift; - }; - 9E2A8BC12B84F106004A81CF /* FirebaseStorage */ = { - isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseStorage; - }; - 9E2A8BC32B84F106004A81CF /* FirebaseStorageCombine-Community */ = { - isa = XCSwiftPackageProductDependency; - package = 9E2A8BAE2B84F106004A81CF /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseStorageCombine-Community"; - }; - 9E4382D82B83746B00C69708 /* GoogleSignIn */ = { - isa = XCSwiftPackageProductDependency; - package = 9E4382D72B83746B00C69708 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; - productName = GoogleSignIn; - }; - 9E4382DA2B83746B00C69708 /* GoogleSignInSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 9E4382D72B83746B00C69708 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; - productName = GoogleSignInSwift; - }; - 9E5B74CB2B7F963100E2BDE6 /* PinLayout */ = { - isa = XCSwiftPackageProductDependency; - package = 9E5B74CA2B7F963100E2BDE6 /* XCRemoteSwiftPackageReference "PinLayout" */; - productName = PinLayout; - }; - 9E673DA52B8275680041B97D /* VKID */ = { - isa = XCSwiftPackageProductDependency; - package = 9E673DA42B8275680041B97D /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */; - productName = VKID; - }; - 9E673DA72B8275680041B97D /* VKIDCore */ = { + CE5E73752B912DA1007620A7 /* M13Checkbox */ = { isa = XCSwiftPackageProductDependency; - package = 9E673DA42B8275680041B97D /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */; - productName = VKIDCore; + package = CE5E73742B912DA1007620A7 /* XCRemoteSwiftPackageReference "M13Checkbox" */; + productName = M13Checkbox; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/Everyday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Everyday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 92ab457..ea3ebad 100644 --- a/Everyday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Everyday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,30 +1,30 @@ { "pins" : [ { - "identity" : "abseil-cpp-binary", + "identity" : "abseil-cpp-swiftpm", "kind" : "remoteSourceControl", - "location" : "https://github.com/google/abseil-cpp-binary.git", + "location" : "https://github.com/firebase/abseil-cpp-SwiftPM.git", "state" : { - "revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c", - "version" : "1.2022062300.0" + "revision" : "583de9bd60f66b40e78d08599cc92036c2e7e4e1", + "version" : "0.20220203.2" } }, { - "identity" : "app-check", + "identity" : "appauth-ios", "kind" : "remoteSourceControl", - "location" : "https://github.com/google/app-check.git", + "location" : "https://github.com/openid/AppAuth-iOS.git", "state" : { - "revision" : "3e464dad87dad2d29bb29a97836789bf0f8f67d2", - "version" : "10.18.1" + "revision" : "71cde449f13d453227e687458144bde372d30fc7", + "version" : "1.6.2" } }, { - "identity" : "appauth-ios", + "identity" : "boringssl-swiftpm", "kind" : "remoteSourceControl", - "location" : "https://github.com/openid/AppAuth-iOS.git", + "location" : "https://github.com/firebase/boringssl-SwiftPM.git", "state" : { - "revision" : "71cde449f13d453227e687458144bde372d30fc7", - "version" : "1.6.2" + "revision" : "dd3eda2b05a3f459fc3073695ad1b28659066eab", + "version" : "0.9.1" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/firebase/firebase-ios-sdk", "state" : { - "revision" : "f91c8167141d0279726c6f6d9d4a47c026785cbc", - "version" : "10.21.0" + "revision" : "7e80c25b51c2ffa238879b07fbfc5baa54bb3050", + "version" : "9.6.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleAppMeasurement.git", "state" : { - "revision" : "cb8617fab75d181270a1d8f763f26b15c73e2e1e", - "version" : "10.21.0" + "revision" : "c1cfde8067668027b23a42c29d11c246152fe046", + "version" : "9.6.0" } }, { @@ -73,12 +73,12 @@ } }, { - "identity" : "grpc-binary", + "identity" : "grpc-ios", "kind" : "remoteSourceControl", - "location" : "https://github.com/google/grpc-binary.git", + "location" : "https://github.com/grpc/grpc-ios.git", "state" : { - "revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98", - "version" : "1.49.1" + "revision" : "8440b914756e0d26d4f4d054a1c1581daedfc5b6", + "version" : "1.44.3-grpc" } }, { @@ -86,8 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/gtm-session-fetcher.git", "state" : { - "revision" : "76135c9f4e1ac85459d5fec61b6f76ac47ab3a4c", - "version" : "3.3.1" + "revision" : "5ccda3981422a84186387dbb763ba739178b529c", + "version" : "2.3.0" } }, { @@ -100,21 +100,21 @@ } }, { - "identity" : "interop-ios-for-google-sdks", + "identity" : "leveldb", "kind" : "remoteSourceControl", - "location" : "https://github.com/google/interop-ios-for-google-sdks.git", + "location" : "https://github.com/firebase/leveldb.git", "state" : { - "revision" : "2d12673670417654f08f5f90fdd62926dc3a2648", - "version" : "100.0.0" + "revision" : "9d108e9112aa1d65ce508facf804674546116d9c", + "version" : "1.22.3" } }, { - "identity" : "leveldb", + "identity" : "m13checkbox", "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/leveldb.git", + "location" : "https://github.com/Marxon13/M13Checkbox", "state" : { - "revision" : "9d108e9112aa1d65ce508facf804674546116d9c", - "version" : "1.22.3" + "revision" : "96ff6c8862db87095315480a56dcebe51e15dac8", + "version" : "3.4.1" } }, { @@ -152,15 +152,6 @@ "revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8", "version" : "1.25.2" } - }, - { - "identity" : "vkid-ios-sdk", - "kind" : "remoteSourceControl", - "location" : "https://github.com/VKCOM/vkid-ios-sdk.git", - "state" : { - "revision" : "ed4b733be37abd273c65406bff709e2f79656dc7", - "version" : "1.2.2" - } } ], "version" : 2 diff --git a/Everyday/Modules/Authorization/OnBoarding/ProfileSetup/ProfileSetupView.swift b/Everyday/Modules/Authorization/OnBoarding/ProfileSetup/ProfileSetupView.swift index 866b2ca..5bdf062 100644 --- a/Everyday/Modules/Authorization/OnBoarding/ProfileSetup/ProfileSetupView.swift +++ b/Everyday/Modules/Authorization/OnBoarding/ProfileSetup/ProfileSetupView.swift @@ -22,38 +22,41 @@ struct ProfileSetupView: View { var body: some View { ScrollView { VStack(spacing: Constants.VStackValues.spacing) { - Spacer() - - Text(AttributedString(viewModel.title)) - .font(.headline) - .multilineTextAlignment(.center) - - Spacer() - - ZStack { - if let inputImage = viewModel.inputImage { - Image(uiImage: inputImage) - .resizable() - .scaledToFill() - } else { - defaultImage - .resizable() - .scaledToFill() + Group { + + Spacer() + + Text(AttributedString(viewModel.title)) + .font(.headline) + .multilineTextAlignment(.center) + + Spacer() + + ZStack { + if let inputImage = viewModel.inputImage { + Image(uiImage: inputImage) + .resizable() + .scaledToFill() + } else { + defaultImage + .resizable() + .scaledToFill() + } } + .frame(width: Constants.ZStackValues.size.width, height: Constants.ZStackValues.size.height) + .clipShape(Circle()) + .overlay(Circle().stroke(Color.primary, lineWidth: Constants.ZStackValues.overlay)) + .padding() + + Button(action: { + viewModel.showingImagePicker = true + }, label: { + Text(AttributedString(viewModel.photoTitle)) + .foregroundColor(Constants.primaryText) + }) + + Spacer() } - .frame(width: Constants.ZStackValues.size.width, height: Constants.ZStackValues.size.height) - .clipShape(Circle()) - .overlay(Circle().stroke(Color.primary, lineWidth: Constants.ZStackValues.overlay)) - .padding() - - Button(action: { - viewModel.showingImagePicker = true - }, label: { - Text(AttributedString(viewModel.photoTitle)) - .foregroundColor(Constants.primaryText) - }) - - Spacer() UserTextField(text: $viewModel.userProfile.name, keyType: .default, placeholder: viewModel.name) .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) diff --git a/Everyday/Modules/Authorization/SignUp/SignUpInteractor.swift b/Everyday/Modules/Authorization/SignUp/SignUpInteractor.swift index 654695d..81ac288 100644 --- a/Everyday/Modules/Authorization/SignUp/SignUpInteractor.swift +++ b/Everyday/Modules/Authorization/SignUp/SignUpInteractor.swift @@ -19,16 +19,16 @@ final class SignUpInteractor { } extension SignUpInteractor: SignUpInteractorInput { - func authWithVKID(completion: @escaping (Result) -> Void) { - guard let viewController = self.viewController else { - completion(.failure(NSError(domain: "AuthError", code: 0, userInfo: [NSLocalizedDescriptionKey: "ViewController is nil"]))) - return - } - - authService.authWithVKID(with: viewController) { result in - completion(result) - } - } +// func authWithVKID(completion: @escaping (Result) -> Void) { +// guard let viewController = self.viewController else { +// completion(.failure(NSError(domain: "AuthError", code: 0, userInfo: [NSLocalizedDescriptionKey: "ViewController is nil"]))) +// return +// } +// +// authService.authWithVKID(with: viewController) { result in +// completion(result) +// } +// } func authWithGoogle(completion: @escaping (Result) -> Void) { guard let viewController = self.viewController else { diff --git a/Everyday/Modules/Authorization/SignUp/SignUpPresenter.swift b/Everyday/Modules/Authorization/SignUp/SignUpPresenter.swift index 0b986c7..6454855 100644 --- a/Everyday/Modules/Authorization/SignUp/SignUpPresenter.swift +++ b/Everyday/Modules/Authorization/SignUp/SignUpPresenter.swift @@ -63,16 +63,16 @@ extension SignUpPresenter: SignUpViewOutput { func didTapSignWithVKButton() { AuthModel.shared.whichSign = .vk - interactor.authWithVKID { result in - DispatchQueue.main.async { - switch result { - case .success: - self.router.openOnBoarding() - case .failure(let error): - self.view?.showAlert(with: "network", message: NSMutableAttributedString(string: error.localizedDescription)) - } - } - } +// interactor.authWithVKID { result in +// DispatchQueue.main.async { +// switch result { +// case .success: +// self.router.openOnBoarding() +// case .failure(let error): +// self.view?.showAlert(with: "network", message: NSMutableAttributedString(string: error.localizedDescription)) +// } +// } +// } } func didTapSignWithGoogleButton() { diff --git a/Everyday/Modules/Authorization/SignUp/SignUpProtocols.swift b/Everyday/Modules/Authorization/SignUp/SignUpProtocols.swift index 69e7771..af62b67 100644 --- a/Everyday/Modules/Authorization/SignUp/SignUpProtocols.swift +++ b/Everyday/Modules/Authorization/SignUp/SignUpProtocols.swift @@ -30,7 +30,7 @@ protocol SignUpViewOutput: AnyObject { protocol SignUpInteractorInput: AnyObject { func authWithGoogle(completion: @escaping (Result) -> Void) - func authWithVKID(completion: @escaping (Result) -> Void) +// func authWithVKID(completion: @escaping (Result) -> Void) } protocol SignUpInteractorOutput: AnyObject { diff --git a/Everyday/Services/Auth/AuthService.swift b/Everyday/Services/Auth/AuthService.swift index f8818a0..cd15256 100644 --- a/Everyday/Services/Auth/AuthService.swift +++ b/Everyday/Services/Auth/AuthService.swift @@ -8,7 +8,7 @@ import UIKit protocol AuthServiceDescription { - func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) +// func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) func authWithGoogle(with presentingController: UIViewController, completion: @escaping (Result) -> Void) func authWithFirebase(with userRequest: ProfileAcknowledgementModel) } @@ -16,23 +16,22 @@ protocol AuthServiceDescription { final class AuthService: AuthServiceDescription { static let shared = AuthService() - private let vkidAuthService: VKIDAuthServiceDescription +// private let vkidAuthService: VKIDAuthServiceDescription private let googleAuthService: GoogleAuthServiceDescription private let firebaseAuthService: FirebaseAuthServiceDescription - private init(vkidAuthService: VKIDAuthServiceDescription = VKIDAuthService.shared, - googleAuthService: GoogleAuthServiceDescription = GoogleAuthService.shared, + private init(googleAuthService: GoogleAuthServiceDescription = GoogleAuthService.shared, firebaseAuthService: FirebaseAuthServiceDescription = FirebaseAuthService.shared ) { - self.vkidAuthService = vkidAuthService +// self.vkidAuthService = vkidAuthService self.googleAuthService = googleAuthService self.firebaseAuthService = firebaseAuthService } - func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { - vkidAuthService.authWithVKID(with: presentingController) { result in - completion(result) - } - } +// func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { +// vkidAuthService.authWithVKID(with: presentingController) { result in +// completion(result) +// } +// } func authWithGoogle(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { googleAuthService.authWithGoogle(with: presentingController) { result in diff --git a/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift b/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift index 1e9e939..ae6a8df 100644 --- a/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift +++ b/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift @@ -6,64 +6,64 @@ // import UIKit -import VKID - -protocol VKIDAuthServiceDescription { - var vkid: VKID? { get } - func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) -} - -final class VKIDAuthService: VKIDAuthServiceDescription { - static let shared = VKIDAuthService() - - var vkid: VKID? - - private init() { - guard - let clientId = InfoPlist.vkClientId, !clientId.isEmpty, - let clientSecret = InfoPlist.vkClientSecret, !clientSecret.isEmpty - else { - preconditionFailure("Info.plist does not contain correct values for CLIENT_ID and CLIENT_SECRET keys") - } - - do { - let vkid = try VKID( - config: Configuration( - appCredentials: AppCredentials( - clientId: clientId, - clientSecret: clientSecret - ) - ) - ) - self.vkid = vkid - } catch { - preconditionFailure("Failed to initialize VKID: \(error)") - } - } - - func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { - vkid?.authorize( - using: .uiViewController(presentingController) - ) { result in - do { - let session = try result.get() - let passwordGenerator = PasswordGenerator(length: 20) - - ProfileAcknowledgementModel.shared.firstname = session.user.firstName - ProfileAcknowledgementModel.shared.lastname = session.user.lastName - ProfileAcknowledgementModel.shared.email = session.user.email - ProfileAcknowledgementModel.shared.password = passwordGenerator.generatePassword() - // session.user.avatarURL - - completion(.success(())) - } catch AuthError.cancelled { - print("Auth cancelled by user") - return - } catch { - let error = NSError(domain: "AuthError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to retrieve user information"]) - completion(.failure(error)) - return - } - } - } -} +//import VKID +// +//protocol VKIDAuthServiceDescription { +// var vkid: VKID? { get } +// func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) +//} +// +//final class VKIDAuthService: VKIDAuthServiceDescription { +// static let shared = VKIDAuthService() +// +// var vkid: VKID? +// +// private init() { +// guard +// let clientId = InfoPlist.vkClientId, !clientId.isEmpty, +// let clientSecret = InfoPlist.vkClientSecret, !clientSecret.isEmpty +// else { +// preconditionFailure("Info.plist does not contain correct values for CLIENT_ID and CLIENT_SECRET keys") +// } +// +// do { +// let vkid = try VKID( +// config: Configuration( +// appCredentials: AppCredentials( +// clientId: clientId, +// clientSecret: clientSecret +// ) +// ) +// ) +// self.vkid = vkid +// } catch { +// preconditionFailure("Failed to initialize VKID: \(error)") +// } +// } +// +// func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { +// vkid?.authorize( +// using: .uiViewController(presentingController) +// ) { result in +// do { +// let session = try result.get() +// let passwordGenerator = PasswordGenerator(length: 20) +// +// ProfileAcknowledgementModel.shared.firstname = session.user.firstName +// ProfileAcknowledgementModel.shared.lastname = session.user.lastName +// ProfileAcknowledgementModel.shared.email = session.user.email +// ProfileAcknowledgementModel.shared.password = passwordGenerator.generatePassword() +// // session.user.avatarURL +// +// completion(.success(())) +// } catch AuthError.cancelled { +// print("Auth cancelled by user") +// return +// } catch { +// let error = NSError(domain: "AuthError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to retrieve user information"]) +// completion(.failure(error)) +// return +// } +// } +// } +//} diff --git a/Everyday/Support/AppDelegate.swift b/Everyday/Support/AppDelegate.swift index b1e5298..573a2e0 100644 --- a/Everyday/Support/AppDelegate.swift +++ b/Everyday/Support/AppDelegate.swift @@ -33,9 +33,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } - if VKIDAuthService.shared.vkid?.open(url: url) == true { - return true - } +// if VKIDAuthService.shared.vkid?.open(url: url) == true { +// return true +// } return false } } diff --git a/Everyday/Support/SceneDelegate.swift b/Everyday/Support/SceneDelegate.swift index 232af31..ac07581 100644 --- a/Everyday/Support/SceneDelegate.swift +++ b/Everyday/Support/SceneDelegate.swift @@ -6,7 +6,7 @@ // import UIKit -import VKID +//import VKID class SceneDelegate: UIResponder, UIWindowSceneDelegate { From 3e336e8b5ce446dd74bf9f009dd3a63a7a8755b5 Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Fri, 1 Mar 2024 09:06:53 +0300 Subject: [PATCH 04/13] swiftlint + welcome skip --- Everyday/Entities/Workout.swift | 2 +- .../OnBoarding/ContentView.swift | 4 +- .../ProfileAcknowledgementView.swift | 426 +++++++++--------- .../NotepadScene/NotepadInteractor.swift | 4 +- .../TrainingScene/TrainingPresenter.swift | 7 +- .../Auth/VKIDAuth/VKIDAuthService.swift | 10 +- Everyday/Services/Day/DayService.swift | 2 +- Everyday/Support/SceneDelegate.swift | 4 +- 8 files changed, 230 insertions(+), 229 deletions(-) diff --git a/Everyday/Entities/Workout.swift b/Everyday/Entities/Workout.swift index 1ac1941..be29937 100644 --- a/Everyday/Entities/Workout.swift +++ b/Everyday/Entities/Workout.swift @@ -63,6 +63,6 @@ struct Mock { Workout(name: "Кардио", days: [ DayOfWorkout(name: "День 1", sets: [ TrainingSet(name: "", exercises: [ - Exercise(name: "Jumping Jacks", description: "", result: "20 раз")])])]), + Exercise(name: "Jumping Jacks", description: "", result: "20 раз")])])]) ] } diff --git a/Everyday/Modules/Authorization/OnBoarding/ContentView.swift b/Everyday/Modules/Authorization/OnBoarding/ContentView.swift index 2e0549a..f5ac98d 100644 --- a/Everyday/Modules/Authorization/OnBoarding/ContentView.swift +++ b/Everyday/Modules/Authorization/OnBoarding/ContentView.swift @@ -52,8 +52,8 @@ struct ContentView: View { }) .tag(6) - ProfileAcknowledgementView(onFinish: onFinish) - .tag(7) +// ProfileAcknowledgementView(onFinish: onFinish) +// .tag(7) } .animation(.easeInOut, value: pageIndex) .indexViewStyle(.page(backgroundDisplayMode: .interactive)) diff --git a/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift b/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift index 0f60e2d..537dce3 100644 --- a/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift +++ b/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift @@ -1,215 +1,215 @@ -import SwiftUI - -struct ProfileAcknowledgementView: View { - - // MARK: - properties - - @StateObject private var viewModel = ProfileAcknowledgementViewModel() - @State private var controller: ProfileAcknowledgementController? - - @State private var selectedAge: Age = .small - @State private var selectedGender: Gender = .male - @State private var selectedWeight = "" - @State private var selectedName = "" - @State private var selectedSurname = "" - @State private var selectedNickname = "" - - private let defaultImage = Image("anonymous") - - var onFinish: (() -> Void)? - - // MARK: - body - - var body: some View { - ScrollView { - VStack(spacing: Constants.VStackValues.spacing) { - Spacer() - - Text(AttributedString(viewModel.title)) - .font(.headline) - .multilineTextAlignment(.center) - .foregroundColor(Constants.primaryText) - - Spacer() - - ZStack { -// if let inputImage = viewModel.inputImage { -// Image(uiImage: inputImage) +// import SwiftUI +// +// struct ProfileAcknowledgementView: View { +// +// // MARK: - properties +// +// @StateObject private var viewModel = ProfileAcknowledgementViewModel() +// @State private var controller: ProfileAcknowledgementController? +// +// @State private var selectedAge: Age = .small +// @State private var selectedGender: Gender = .male +// @State private var selectedWeight = "" +// @State private var selectedName = "" +// @State private var selectedSurname = "" +// @State private var selectedNickname = "" +// +// private let defaultImage = Image("anonymous") +// +// var onFinish: (() -> Void)? +// +// // MARK: - body +// +// var body: some View { +// ScrollView { +// VStack(spacing: Constants.VStackValues.spacing) { +// Spacer() +// +// Text(AttributedString(viewModel.title)) +// .font(.headline) +// .multilineTextAlignment(.center) +// .foregroundColor(Constants.primaryText) +// +// Spacer() +// +// ZStack { +//// if let inputImage = viewModel.inputImage { +//// Image(uiImage: inputImage) +//// .resizable() +//// .scaledToFill() +//// } else { +// defaultImage // .resizable() // .scaledToFill() -// } else { - defaultImage - .resizable() - .scaledToFill() -// } - } - .frame(width: Constants.ZStackValues.size.width, height: Constants.ZStackValues.size.height) - .clipShape(Circle()) - .overlay(Circle().stroke(Color.primary, lineWidth: Constants.ZStackValues.overlay)) - .padding() - - Button(action: { - viewModel.showingImagePicker = true - }, label: { - Text(AttributedString(viewModel.photoTitle)) - .foregroundColor(Constants.primaryText) - }) - - Spacer() - - UserTextField(text: $selectedName, keyType: .default, placeholder: viewModel.name) - .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) - .padding(.horizontal, Constants.TextFieldValues.hPadding) - .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) - .cornerRadius(Constants.TextFieldValues.cornerRadius) - - UserTextField(text: $selectedSurname, keyType: .default, placeholder: viewModel.surname) - .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) - .padding(.horizontal, Constants.TextFieldValues.hPadding) - .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) - .cornerRadius(Constants.TextFieldValues.cornerRadius) - - UserTextField(text: $selectedNickname, keyType: .default, placeholder: viewModel.nickname) - .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) - .padding(.horizontal, Constants.TextFieldValues.hPadding) - .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) - .cornerRadius(Constants.TextFieldValues.cornerRadius) - - Spacer() - - Text(AttributedString(viewModel.ageConfirm)) - .font(.headline) - .multilineTextAlignment(.center) - .foregroundColor(Color.primaryText) - - ForEach(controller?.ages ?? [], id: \.self) { age in - let ageText = viewModel.ageText(for: age) - AgeButtonView(age: age, ageText: ageText, selectedAge: $selectedAge ) - } - - Spacer() - - Text(AttributedString(viewModel.genderConfirm)) - .font(.subheadline) - .multilineTextAlignment(.center) - .foregroundColor(Constants.primaryText) - - ForEach(viewModel.gendersUI, id: \.gender) { genderUI in - GenderButtonView( - gender: genderUI.gender, - imageName: genderUI.imageName, - localizedText: genderUI.localizedText, - selectedGender: $selectedGender - ) - } - - Spacer() - - Text(AttributedString(viewModel.weightConfirm)) - .font(.headline) - .multilineTextAlignment(.center) - .foregroundColor(Color.primaryText) - - DecimalTextField(text: $selectedWeight, keyType: .numberPad, placeholder: viewModel.placeholder) - .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) - .padding(.horizontal, Constants.TextFieldValues.hPadding) - .background(Color.gray.opacity(Constants.TextFieldValues.colorOpacity)) - .cornerRadius(Constants.TextFieldValues.cornerRadius) - - Spacer() - - Button(action: { - - saveDataToModel() - - AuthService.shared.authWithFirebase(with: ProfileAcknowledgementModel.shared) - - onFinish?() - }, label: { - Text(AttributedString(viewModel.starter)) - .padding(.horizontal, Constants.ButtonValues.hPadding) - .padding(.vertical, Constants.ButtonValues.vPadding) - .frame(maxWidth: .infinity) - .background(Constants.accent) - .foregroundColor(Constants.button) - .cornerRadius(Constants.ButtonValues.cornerRadius) - }) - - .padding(.bottom, Constants.VStackValues.bPadding) - } - .padding(.horizontal) - .sheet(isPresented: $viewModel.showingImagePicker, onDismiss: viewModel.loadImage) { - ImagePicker(image: self.$viewModel.inputImage) - } - } - .scrollIndicators(.hidden) - .onAppear { - let ageEnum = Age.from(description: ProfileAcknowledgementModel.shared.age ?? "") ?? .small - let genderEnum = Gender.from(description: ProfileAcknowledgementModel.shared.gender ?? "") ?? .male - let weight = ProfileAcknowledgementModel.shared.weight - let name = ProfileAcknowledgementModel.shared.firstname - let surname = ProfileAcknowledgementModel.shared.lastname - let nickname = ProfileAcknowledgementModel.shared.nickname - - self.controller = ProfileAcknowledgementController(ageDescription: ageEnum.description, - genderDescription: genderEnum.description, - weight: weight, - name: name, - surname: surname, - nickname: nickname) - - self.selectedAge = controller?.selectedAge ?? .small - self.selectedGender = controller?.selectedGender ?? .male - self.selectedWeight = controller?.weight ?? "0" - self.selectedName = controller?.name ?? "" - self.selectedSurname = controller?.surname ?? "" - self.selectedNickname = controller?.nickname ?? "" - } - } - - func saveDataToModel() { - ProfileAcknowledgementModel.shared.firstname = selectedName - ProfileAcknowledgementModel.shared.lastname = selectedSurname - ProfileAcknowledgementModel.shared.nickname = selectedNickname - ProfileAcknowledgementModel.shared.profileImage = viewModel.inputImage - ProfileAcknowledgementModel.shared.age = selectedAge.description - ProfileAcknowledgementModel.shared.gender = selectedGender.description - ProfileAcknowledgementModel.shared.weight = selectedWeight - } -} - -// MARK: - extensions - -private extension ProfileAcknowledgementView { - struct Constants { - - static let primaryText = Color.primaryText - static let accent = Color.accent - static let clear = Color.clear - static let gray = Color.gray - static let button = Color.grayElement - - struct VStackValues { - static let spacing: CGFloat = 15 - static let bPadding: CGFloat = 65 - } - - struct ZStackValues { - static let size: CGSize = CGSize(width: 150, height: 150) - static let overlay: CGFloat = 0.5 - } - - struct ButtonValues { - static let hPadding: CGFloat = 100 - static let vPadding: CGFloat = 16 - static let cornerRadius: CGFloat = 20 - } - - struct TextFieldValues { - static let size: CGSize = CGSize(width: 300, height: 50) - static let hPadding: CGFloat = 24 - static let cornerRadius: CGFloat = 8 - static let colorOpacity: CGFloat = 0.1 - } - } -} +//// } +// } +// .frame(width: Constants.ZStackValues.size.width, height: Constants.ZStackValues.size.height) +// .clipShape(Circle()) +// .overlay(Circle().stroke(Color.primary, lineWidth: Constants.ZStackValues.overlay)) +// .padding() +// +// Button(action: { +// viewModel.showingImagePicker = true +// }, label: { +// Text(AttributedString(viewModel.photoTitle)) +// .foregroundColor(Constants.primaryText) +// }) +// +// Spacer() +// +// UserTextField(text: $selectedName, keyType: .default, placeholder: viewModel.name) +// .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) +// .padding(.horizontal, Constants.TextFieldValues.hPadding) +// .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) +// .cornerRadius(Constants.TextFieldValues.cornerRadius) +// +// UserTextField(text: $selectedSurname, keyType: .default, placeholder: viewModel.surname) +// .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) +// .padding(.horizontal, Constants.TextFieldValues.hPadding) +// .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) +// .cornerRadius(Constants.TextFieldValues.cornerRadius) +// +// UserTextField(text: $selectedNickname, keyType: .default, placeholder: viewModel.nickname) +// .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) +// .padding(.horizontal, Constants.TextFieldValues.hPadding) +// .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) +// .cornerRadius(Constants.TextFieldValues.cornerRadius) +// +// Spacer() +// +// Text(AttributedString(viewModel.ageConfirm)) +// .font(.headline) +// .multilineTextAlignment(.center) +// .foregroundColor(Color.primaryText) +// +// ForEach(controller?.ages ?? [], id: \.self) { age in +// let ageText = viewModel.ageText(for: age) +// AgeButtonView(age: age, ageText: ageText, selectedAge: $selectedAge ) +// } +// +// Spacer() +// +// Text(AttributedString(viewModel.genderConfirm)) +// .font(.subheadline) +// .multilineTextAlignment(.center) +// .foregroundColor(Constants.primaryText) +// +// ForEach(viewModel.gendersUI, id: \.gender) { genderUI in +// GenderButtonView( +// gender: genderUI.gender, +// imageName: genderUI.imageName, +// localizedText: genderUI.localizedText, +// selectedGender: $selectedGender +// ) +// } +// +// Spacer() +// +// Text(AttributedString(viewModel.weightConfirm)) +// .font(.headline) +// .multilineTextAlignment(.center) +// .foregroundColor(Color.primaryText) +// +// DecimalTextField(text: $selectedWeight, keyType: .numberPad, placeholder: viewModel.placeholder) +// .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) +// .padding(.horizontal, Constants.TextFieldValues.hPadding) +// .background(Color.gray.opacity(Constants.TextFieldValues.colorOpacity)) +// .cornerRadius(Constants.TextFieldValues.cornerRadius) +// +// Spacer() +// +// Button(action: { +// +// saveDataToModel() +// +// AuthService.shared.authWithFirebase(with: ProfileAcknowledgementModel.shared) +// +// onFinish?() +// }, label: { +// Text(AttributedString(viewModel.starter)) +// .padding(.horizontal, Constants.ButtonValues.hPadding) +// .padding(.vertical, Constants.ButtonValues.vPadding) +// .frame(maxWidth: .infinity) +// .background(Constants.accent) +// .foregroundColor(Constants.button) +// .cornerRadius(Constants.ButtonValues.cornerRadius) +// }) +// +// .padding(.bottom, Constants.VStackValues.bPadding) +// } +// .padding(.horizontal) +// .sheet(isPresented: $viewModel.showingImagePicker, onDismiss: viewModel.loadImage) { +// ImagePicker(image: self.$viewModel.inputImage) +// } +// } +// .scrollIndicators(.hidden) +// .onAppear { +// let ageEnum = Age.from(description: ProfileAcknowledgementModel.shared.age ?? "") ?? .small +// let genderEnum = Gender.from(description: ProfileAcknowledgementModel.shared.gender ?? "") ?? .male +// let weight = ProfileAcknowledgementModel.shared.weight +// let name = ProfileAcknowledgementModel.shared.firstname +// let surname = ProfileAcknowledgementModel.shared.lastname +// let nickname = ProfileAcknowledgementModel.shared.nickname +// +// self.controller = ProfileAcknowledgementController(ageDescription: ageEnum.description, +// genderDescription: genderEnum.description, +// weight: weight, +// name: name, +// surname: surname, +// nickname: nickname) +// +// self.selectedAge = controller?.selectedAge ?? .small +// self.selectedGender = controller?.selectedGender ?? .male +// self.selectedWeight = controller?.weight ?? "0" +// self.selectedName = controller?.name ?? "" +// self.selectedSurname = controller?.surname ?? "" +// self.selectedNickname = controller?.nickname ?? "" +// } +// } +// +// func saveDataToModel() { +// ProfileAcknowledgementModel.shared.firstname = selectedName +// ProfileAcknowledgementModel.shared.lastname = selectedSurname +// ProfileAcknowledgementModel.shared.nickname = selectedNickname +// ProfileAcknowledgementModel.shared.profileImage = viewModel.inputImage +// ProfileAcknowledgementModel.shared.age = selectedAge.description +// ProfileAcknowledgementModel.shared.gender = selectedGender.description +// ProfileAcknowledgementModel.shared.weight = selectedWeight +// } +// } +// +// // MARK: - extensions +// +// private extension ProfileAcknowledgementView { +// struct Constants { +// +// static let primaryText = Color.primaryText +// static let accent = Color.accent +// static let clear = Color.clear +// static let gray = Color.gray +// static let button = Color.grayElement +// +// struct VStackValues { +// static let spacing: CGFloat = 15 +// static let bPadding: CGFloat = 65 +// } +// +// struct ZStackValues { +// static let size: CGSize = CGSize(width: 150, height: 150) +// static let overlay: CGFloat = 0.5 +// } +// +// struct ButtonValues { +// static let hPadding: CGFloat = 100 +// static let vPadding: CGFloat = 16 +// static let cornerRadius: CGFloat = 20 +// } +// +// struct TextFieldValues { +// static let size: CGSize = CGSize(width: 300, height: 50) +// static let hPadding: CGFloat = 24 +// static let cornerRadius: CGFloat = 8 +// static let colorOpacity: CGFloat = 0.1 +// } +// } +// } diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift index 60bf666..8d29483 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift @@ -28,7 +28,7 @@ extension NotepadInteractor: NotepadInteractorInput { switch result { case .success(let workoutDays): self.output?.didLoadDay(with: workoutDays, true) - case .failure(let error): + case .failure: self.loadSchedule() } } @@ -43,7 +43,7 @@ extension NotepadInteractor: NotepadInteractorInput { switch result { case .success(let workoutDays): self.output?.didLoadDay(with: workoutDays, false) - case .failure(let error): + case .failure: break } } diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift index c0a0683..1f252b3 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift @@ -47,7 +47,7 @@ extension TrainingPresenter: TrainingViewOutput { func setSwitchState(at index: Int, with value: Bool) { switchStates[index] = value - let allSatisfy = switchStates.allSatisfy{ $0 } + let allSatisfy = switchStates.allSatisfy { $0 } if allSatisfy { view?.showFinishButton() } else { @@ -82,11 +82,12 @@ extension TrainingPresenter: TrainingViewOutput { extension TrainingPresenter: ExerciseModuleOutput { func setResult(of exercise: String, with result: String, at indexOfSet: Int) { - guard let exerciseNumber1 = self.workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises.firstIndex(where: { $0.name == exercise }) else { + let exercises = self.workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises + guard let indexOfExercise = exercises.firstIndex(where: { $0.name == exercise }) else { return } - self.workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises[exerciseNumber1].result = result + self.workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises[indexOfExercise].result = result view?.reloadData() } } diff --git a/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift b/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift index ae6a8df..0108167 100644 --- a/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift +++ b/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift @@ -6,14 +6,14 @@ // import UIKit -//import VKID +// import VKID // -//protocol VKIDAuthServiceDescription { +// protocol VKIDAuthServiceDescription { // var vkid: VKID? { get } // func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) -//} +// } // -//final class VKIDAuthService: VKIDAuthServiceDescription { +// final class VKIDAuthService: VKIDAuthServiceDescription { // static let shared = VKIDAuthService() // // var vkid: VKID? @@ -66,4 +66,4 @@ import UIKit // } // } // } -//} +// } diff --git a/Everyday/Services/Day/DayService.swift b/Everyday/Services/Day/DayService.swift index e11a3bc..0e4b2e1 100644 --- a/Everyday/Services/Day/DayService.swift +++ b/Everyday/Services/Day/DayService.swift @@ -27,7 +27,7 @@ final class DayService: DayServiceDescription { func getDayResults(on date: Date, completion: @escaping (Result<[(workout: Workout, indexOfDay: Int)], CustomError>) -> Void) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - let workoutDays = MockSchedule.mockSchedule.daysOfWeek[4] +// let workoutDays = MockSchedule.mockSchedule.daysOfWeek[4] // let result: Result<[(workout: Workout, indexOfDay: Int)], CustomError> = .success(workoutDays) let result: Result<[(workout: Workout, indexOfDay: Int)], CustomError> = .failure(.unknownError) completion(result) diff --git a/Everyday/Support/SceneDelegate.swift b/Everyday/Support/SceneDelegate.swift index ac07581..6b5ca53 100644 --- a/Everyday/Support/SceneDelegate.swift +++ b/Everyday/Support/SceneDelegate.swift @@ -6,7 +6,7 @@ // import UIKit -//import VKID +// import VKID class SceneDelegate: UIResponder, UIWindowSceneDelegate { @@ -17,7 +17,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { return } - let viewController = WelcomeScreenContainer.assemble(with: .init()).viewController + let viewController = NotepadContainer.assemble(with: .init()).viewController let navigationController = UINavigationController(rootViewController: viewController) let window = UIWindow(windowScene: scene) From 71db2b3048eb5d69dc8c13732353e4aa0e7a049a Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Sat, 2 Mar 2024 18:22:23 +0300 Subject: [PATCH 05/13] constants+new view models --- Everyday.xcodeproj/project.pbxproj | 16 +++ .../ExerciseViewController.swift | 51 +++++++--- .../Models/NotepadHeaderViewModel.swift | 41 ++++++++ .../NotepadTableViewCellViewModel.swift | 37 +++++++ .../Models/NotepadViewModel.swift | 1 + .../NotepadSectionHeaderView.swift | 53 +++++----- .../NotepadScene/NotepadTableViewCell.swift | 37 +++++-- .../NotepadScene/NotepadViewController.swift | 54 ++++++++--- .../ResultsTableViewCellViewModel.swift | 45 +++++++++ .../Models/ResultsViewModel.swift | 24 +++-- .../ResultsScene/ResultsProtocols.swift | 1 - .../ResultsScene/ResultsTableViewCell.swift | 73 ++++++++++---- .../ResultsScene/ResultsViewController.swift | 97 +++++++++++++------ .../TimerScene/TimerViewController.swift | 52 ++++++---- .../TrainingTableViewCellViewModel.swift | 41 ++++++++ .../TrainingScene/TrainingTableViewCell.swift | 59 +++++++---- .../TrainingViewController.swift | 41 ++++++-- 17 files changed, 561 insertions(+), 162 deletions(-) create mode 100644 Everyday/Modules/Notepad/NotepadScene/Models/NotepadHeaderViewModel.swift create mode 100644 Everyday/Modules/Notepad/NotepadScene/Models/NotepadTableViewCellViewModel.swift create mode 100644 Everyday/Modules/Notepad/ResultsScene/Models/ResultsTableViewCellViewModel.swift create mode 100644 Everyday/Modules/Notepad/TrainingScene/Models/TrainingTableViewCellViewModel.swift diff --git a/Everyday.xcodeproj/project.pbxproj b/Everyday.xcodeproj/project.pbxproj index 5687119..475e02c 100644 --- a/Everyday.xcodeproj/project.pbxproj +++ b/Everyday.xcodeproj/project.pbxproj @@ -106,6 +106,10 @@ CE5E73712B9129C9007620A7 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73702B9129C9007620A7 /* FirebaseAuth */; }; CE5E73732B9129C9007620A7 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73722B9129C9007620A7 /* FirebaseFirestore */; }; CE5E73762B912DA1007620A7 /* M13Checkbox in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73752B912DA1007620A7 /* M13Checkbox */; }; + CE8BF53E2B93302400A0A963 /* NotepadHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8BF53D2B93302400A0A963 /* NotepadHeaderViewModel.swift */; }; + CE8BF5402B93603400A0A963 /* NotepadTableViewCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8BF53F2B93603400A0A963 /* NotepadTableViewCellViewModel.swift */; }; + CE8BF5422B93665B00A0A963 /* TrainingTableViewCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8BF5412B93665B00A0A963 /* TrainingTableViewCellViewModel.swift */; }; + CE8BF5442B9372E700A0A963 /* ResultsTableViewCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8BF5432B9372E700A0A963 /* ResultsTableViewCellViewModel.swift */; }; CEED457A2B8F693E00DD4058 /* CustomError.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED45792B8F693E00DD4058 /* CustomError.swift */; }; CEED457D2B8F69C500DD4058 /* DayService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED457C2B8F69C500DD4058 /* DayService.swift */; }; CEED45802B8F6A7B00DD4058 /* Workout.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEED457F2B8F6A7B00DD4058 /* Workout.swift */; }; @@ -251,6 +255,10 @@ 9EE8AE332B7FB96E001D126F /* WorkoutProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutProtocols.swift; sourceTree = ""; }; 9EE8AE342B7FB96E001D126F /* WorkoutInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutInteractor.swift; sourceTree = ""; }; 9EE8AE352B7FB96E001D126F /* WorkoutContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutContainer.swift; sourceTree = ""; }; + CE8BF53D2B93302400A0A963 /* NotepadHeaderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotepadHeaderViewModel.swift; sourceTree = ""; }; + CE8BF53F2B93603400A0A963 /* NotepadTableViewCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotepadTableViewCellViewModel.swift; sourceTree = ""; }; + CE8BF5412B93665B00A0A963 /* TrainingTableViewCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrainingTableViewCellViewModel.swift; sourceTree = ""; }; + CE8BF5432B9372E700A0A963 /* ResultsTableViewCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultsTableViewCellViewModel.swift; sourceTree = ""; }; CEED45792B8F693E00DD4058 /* CustomError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomError.swift; sourceTree = ""; }; CEED457C2B8F69C500DD4058 /* DayService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayService.swift; sourceTree = ""; }; CEED457F2B8F6A7B00DD4058 /* Workout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Workout.swift; sourceTree = ""; }; @@ -735,6 +743,8 @@ isa = PBXGroup; children = ( CEED45852B8F6B6C00DD4058 /* NotepadViewModel.swift */, + CE8BF53D2B93302400A0A963 /* NotepadHeaderViewModel.swift */, + CE8BF53F2B93603400A0A963 /* NotepadTableViewCellViewModel.swift */, ); path = Models; sourceTree = ""; @@ -758,6 +768,7 @@ isa = PBXGroup; children = ( CEED45992B8F6DE200DD4058 /* TrainingViewModel.swift */, + CE8BF5412B93665B00A0A963 /* TrainingTableViewCellViewModel.swift */, ); path = Models; sourceTree = ""; @@ -803,6 +814,7 @@ isa = PBXGroup; children = ( CEED45BC2B8F6FA300DD4058 /* ResultsViewModel.swift */, + CE8BF5432B9372E700A0A963 /* ResultsTableViewCellViewModel.swift */, ); path = Models; sourceTree = ""; @@ -963,6 +975,7 @@ files = ( CEED45A52B8F6EF500DD4058 /* ExercisePresenter.swift in Sources */, CEED45BA2B8F6F9300DD4058 /* ResultsContainer.swift in Sources */, + CE8BF5402B93603400A0A963 /* NotepadTableViewCellViewModel.swift in Sources */, CEED45DB2B8F708100DD4058 /* ExtraInteractor.swift in Sources */, CEED45BF2B8F6FDB00DD4058 /* ResultsTableViewCell.swift in Sources */, CEED45DF2B8F70BB00DD4058 /* ExtraViewModel.swift in Sources */, @@ -985,6 +998,7 @@ 9E5B74ED2B7F99FB00E2BDE6 /* WelcomeScreenViewModel.swift in Sources */, 9E5B75382B7F9D7600E2BDE6 /* GenderModel.swift in Sources */, CEED45822B8F6A8F00DD4058 /* User.swift in Sources */, + CE8BF5442B9372E700A0A963 /* ResultsTableViewCellViewModel.swift in Sources */, 9E5B754B2B7F9D7600E2BDE6 /* ProfileSetupViewModel.swift in Sources */, 9EE8AE2B2B7FB930001D126F /* NotepadViewController.swift in Sources */, 9E5B75422B7F9D7600E2BDE6 /* AgeController.swift in Sources */, @@ -1036,6 +1050,7 @@ CEED45942B8F6DCE00DD4058 /* TrainingViewController.swift in Sources */, 9E5B75472B7F9D7600E2BDE6 /* ProfileAcknowledgementModel.swift in Sources */, 9E7C19992B8CC3E80006D48C /* NameGenerator.swift in Sources */, + CE8BF53E2B93302400A0A963 /* NotepadHeaderViewModel.swift in Sources */, 9E5B74FA2B7F9A7000E2BDE6 /* SignUpProtocols.swift in Sources */, 9EE8AE202B7FB905001D126F /* ProgressInteractor.swift in Sources */, 9E53FB4E2B7F950B00C55A45 /* Color+Extension.swift in Sources */, @@ -1091,6 +1106,7 @@ 9E5B754C2B7F9D7600E2BDE6 /* ProfileSetupModel.swift in Sources */, CEED45952B8F6DCE00DD4058 /* TrainingProtocols.swift in Sources */, 9EE8AE2C2B7FB930001D126F /* NotepadProtocols.swift in Sources */, + CE8BF5422B93665B00A0A963 /* TrainingTableViewCellViewModel.swift in Sources */, 9E5B74EE2B7F99FB00E2BDE6 /* WelcomeScreenPresenter.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Everyday/Modules/Notepad/ExerciseScene/ExerciseViewController.swift b/Everyday/Modules/Notepad/ExerciseScene/ExerciseViewController.swift index 470ca67..bd2fedc 100644 --- a/Everyday/Modules/Notepad/ExerciseScene/ExerciseViewController.swift +++ b/Everyday/Modules/Notepad/ExerciseScene/ExerciseViewController.swift @@ -53,22 +53,22 @@ private extension ExerciseViewController { func layout() { resultLabel.pin .top(view.pin.safeArea) - .marginTop(300) - .horizontally(20) - .height(30) + .marginTop(Constants.ResultLabel.marginTop) + .horizontally(Constants.horizontalMargin) + .height(Constants.contentHeight) counterStepper.pin .below(of: resultLabel) + .width(Constants.CounterStepper.width) + .height(Constants.contentHeight) .hCenter() - .width(100) - .height(40) saveButton.pin .below(of: counterStepper) - .marginTop(40) + .marginTop(Constants.SaveButton.marginTop) + .width(Constants.SaveButton.width) + .height(Constants.contentHeight) .hCenter() - .width(100) - .height(40) } // MARK: - Setup @@ -77,13 +77,13 @@ private extension ExerciseViewController { setupView() setupResultLabel() setupStepper() - setupButton() + setupSaveButton() view.addSubviews(resultLabel, counterStepper, saveButton) } func setupView() { - view.backgroundColor = .systemBackground + view.backgroundColor = Constants.backgroundColor } func setupResultLabel() { @@ -94,8 +94,9 @@ private extension ExerciseViewController { counterStepper.addTarget(self, action: #selector(didTapStepper), for: .touchUpInside) } - func setupButton() { - saveButton.backgroundColor = .systemBlue + func setupSaveButton() { + saveButton.backgroundColor = Constants.SaveButton.backgroundColor + saveButton.layer.cornerRadius = Constants.SaveButton.cornerRadius saveButton.addTarget(self, action: #selector(didTapSaveButton), for: .touchUpInside) } @@ -126,3 +127,29 @@ extension ExerciseViewController: ExerciseViewInput { resultLabel.text = result } } + +// MARK: - Constants + +private extension ExerciseViewController { + struct Constants { + static let backgroundColor: UIColor = UIColor.background + + static let horizontalMargin: CGFloat = 20 + static let contentHeight: CGFloat = 40 + + struct ResultLabel { + static let marginTop: CGFloat = 300 + } + + struct CounterStepper { + static let width: CGFloat = 100 + } + + struct SaveButton { + static let backgroundColor: UIColor = UIColor.UI.accent + static let cornerRadius: CGFloat = 16 + static let width: CGFloat = 100 + static let marginTop: CGFloat = 40 + } + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/Models/NotepadHeaderViewModel.swift b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadHeaderViewModel.swift new file mode 100644 index 0000000..81bfd85 --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadHeaderViewModel.swift @@ -0,0 +1,41 @@ +// +// NotepadHeaderViewModel.swift +// Everyday +// +// Created by user on 02.03.2024. +// + +import UIKit + +struct NotepadHeaderViewModel { + let title: NSAttributedString + let desciption: NSAttributedString + let collapseImage: UIImage? + + init(workoutDay: (workout: Workout, indexOfDay: Int)) { + let titleLabelTitle = workoutDay.workout.name + let titleLabelAttributedString = NSAttributedString(string: titleLabelTitle, attributes: Styles.titleAttributes) + let desciptionLabelTitle = workoutDay.workout.name + let desciptionLabelAttributedString = NSAttributedString(string: desciptionLabelTitle, attributes: Styles.desciptionAttributes) + let collapseButtonImageName = "chevron.down" + let collapseButtonImage = UIImage(systemName: collapseButtonImageName) + + self.title = titleLabelAttributedString + self.desciption = desciptionLabelAttributedString + self.collapseImage = collapseButtonImage + } +} + +private extension NotepadHeaderViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.primary, + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + + static let desciptionAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.grayElement, + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/Models/NotepadTableViewCellViewModel.swift b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadTableViewCellViewModel.swift new file mode 100644 index 0000000..2b010e8 --- /dev/null +++ b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadTableViewCellViewModel.swift @@ -0,0 +1,37 @@ +// +// NotepadTableViewCellViewModel.swift +// Everyday +// +// Created by user on 02.03.2024. +// + +import UIKit + +struct NotepadTableViewCellViewModel { + let title: NSAttributedString + let result: NSAttributedString + + init(exercise: Exercise) { + let titleLabelTitle = exercise.name + let titleLabelAttributedString = NSAttributedString(string: titleLabelTitle, attributes: Styles.titleAttributes) + let resultLabelTitle = exercise.result + let resultLabelAttributedString = NSAttributedString(string: resultLabelTitle, attributes: Styles.resultAttributes) + + self.title = titleLabelAttributedString + self.result = resultLabelAttributedString + } +} + +private extension NotepadTableViewCellViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.primary, + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + + static let resultAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.primary, + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift index f8f7b3b..b7a883e 100644 --- a/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift +++ b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift @@ -21,6 +21,7 @@ struct NotepadViewModel { private extension NotepadViewModel { struct Styles { static let titleAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.primary, .font: UIFont.systemFont(ofSize: 24, weight: .regular) ] } diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadSectionHeaderView.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadSectionHeaderView.swift index e78d82b..85cd73d 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadSectionHeaderView.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadSectionHeaderView.swift @@ -43,12 +43,14 @@ class NotepadSectionHeaderView: UIView { // MARK: - Interface - func configure(with workoutDay: (workout: Workout, indexOfDay: Int), and tag: Int, state: NotepadSectionHeaderState) { - titleLabel.text = workoutDay.workout.name - descriptionLabel.text = workoutDay.workout.days[workoutDay.indexOfDay].name + func configure(with viewModel: NotepadHeaderViewModel, and tag: Int, state: NotepadSectionHeaderState) { + titleLabel.attributedText = viewModel.title + descriptionLabel.attributedText = viewModel.desciption + collapseButton.setImage(viewModel.collapseImage, for: .normal) self.tag = tag collapseButton.tag = tag + self.state = state } @@ -79,44 +81,37 @@ private extension NotepadSectionHeaderView { self.addSubview(mainStackView) mainStackView.pin - .horizontally(20) - .vertically(10) + .horizontally(Constants.horizontalMargin) + .vertically(Constants.verticalMargin) } // MARK: - Setup func setup() { setupView() - setupTitleLabel() - setupDescriptionLabel() setupCollapseButton() } func setupView() { - self.backgroundColor = .systemBackground - - self.layer.borderColor = UIColor.label.cgColor - self.layer.borderWidth = 1 - - self.layer.cornerRadius = 16 - self.layer.shadowColor = UIColor.black.cgColor - self.layer.shadowOpacity = 0.3 - self.layer.shadowOffset = .zero - } - - func setupTitleLabel() { - titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .regular) - titleLabel.textColor = .label - } - - func setupDescriptionLabel() { - descriptionLabel.font = UIFont.systemFont(ofSize: 16, weight: .regular) - descriptionLabel.textColor = .secondaryLabel + self.backgroundColor = Constants.backgroundColor + self.layer.cornerRadius = Constants.cornerRadius } func setupCollapseButton() { - let buttonImage = UIImage(systemName: "chevron.down") - collapseButton.setImage(buttonImage, for: .normal) - collapseButton.tintColor = .label + collapseButton.tintColor = Constants.tintColor + } +} + +// MARK: - Constants + +private extension NotepadSectionHeaderView { + struct Constants { + static let backgroundColor: UIColor = UIColor.UI.accent + static let tintColor: UIColor = UIColor.Text.primary + + static let horizontalMargin: CGFloat = 20 + static let verticalMargin: CGFloat = 10 + + static let cornerRadius: CGFloat = 16 } } diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadTableViewCell.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadTableViewCell.swift index 48055c0..a32e5e3 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadTableViewCell.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadTableViewCell.swift @@ -36,9 +36,9 @@ class NotepadTableViewCell: UITableViewCell { // MARK: - Interface - func configure(with exercise: Exercise) { - titleLabel.text = exercise.name - resultLabel.text = exercise.result + func configure(with viewModel: NotepadTableViewCellViewModel) { + titleLabel.attributedText = viewModel.title + resultLabel.attributedText = viewModel.result } } @@ -48,16 +48,16 @@ private extension NotepadTableViewCell { func layout() { titleLabel.pin - .left(10) + .left(Constants.horizontalMargin) .vCenter() - .width(200) - .height(20) + .width(Constants.TitleLabel.width) + .height(Constants.contentHeight) resultLabel.pin - .right(10) + .right(Constants.horizontalMargin) .vCenter() - .width(100) - .height(20) + .width(Constants.ResultLabel.width) + .height(Constants.contentHeight) } // MARK: - Setup @@ -68,3 +68,22 @@ private extension NotepadTableViewCell { contentView.addSubviews(titleLabel, resultLabel) } } + +// MARK: - Constants + +private extension NotepadTableViewCell { + struct Constants { + static let backgroundColor: UIColor = UIColor.UI.accentLight + + static let horizontalMargin: CGFloat = 10 + static let contentHeight: CGFloat = 20 + + struct TitleLabel { + static let width: CGFloat = 200 + } + + struct ResultLabel { + static let width: CGFloat = 100 + } + } +} diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift index 009e7b0..f6d8d50 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift @@ -51,13 +51,13 @@ private extension NotepadViewController { func layout() { stateLabel.pin - .top(view.pin.safeArea).marginTop(200) - .horizontally(20) - .height(30) + .top(view.pin.safeArea) + .horizontally(Constants.HeaderLabel.horizontalMargin) + .height(Constants.HeaderLabel.height) tableView.pin .below(of: stateLabel) - .marginTop(10) + .marginTop(Constants.TableView.marginTop) .horizontally() .bottom() } @@ -72,13 +72,16 @@ private extension NotepadViewController { } func setupView() { - view.backgroundColor = .systemBackground + view.backgroundColor = Constants.backgroundColor navigationItem.leftBarButtonItem = UIBarButtonItem(customView: dateLabel()) } func setupTableView() { - tableView.backgroundColor = .systemBackground - tableView.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0) + tableView.backgroundColor = Constants.backgroundColor + tableView.contentInset = UIEdgeInsets(top: Constants.TableView.contentInsetTop, + left: Constants.TableView.contentInsetLeft, + bottom: Constants.TableView.contentInsetBottom, + right: Constants.TableView.contentInsetRight) tableView.dataSource = self tableView.delegate = self tableView.register(NotepadTableViewCell.self, forCellReuseIdentifier: NotepadTableViewCell.reuseID) @@ -86,8 +89,7 @@ private extension NotepadViewController { func dateLabel() -> UILabel { let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "EEEE, MMM d" - dateFormatter.locale = Locale(identifier: "ru_RU") + dateFormatter.dateFormat = Constants.DateLabel.dateFormat let currentDate = dateFormatter.string(from: Date()) @@ -144,7 +146,8 @@ extension NotepadViewController: UITableViewDataSource { } let exercise = output.getExercise(at: indexPath.section, at: indexPath.row) - cell.configure(with: exercise) + let viewModel = NotepadTableViewCellViewModel(exercise: exercise) + cell.configure(with: viewModel) return cell } @@ -157,15 +160,16 @@ extension NotepadViewController: UITableViewDelegate { let headerView = NotepadSectionHeaderView() let workoutDay = output.getWorkoutDay(section) + let viewModel = NotepadHeaderViewModel(workoutDay: workoutDay) let headerViewState = output.headerViewState() - headerView.configure(with: workoutDay, and: section, state: headerViewState) + headerView.configure(with: viewModel, and: section, state: headerViewState) headerView.addActions(self, viewAction: #selector(didTapHeaderView), buttonAction: #selector(didTapCollapseButton)) return headerView } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return 60 + Constants.TableView.headerHeight } } @@ -186,3 +190,29 @@ extension NotepadViewController: NotepadViewInput { } } } + +// MARK: - Constants + +private extension NotepadViewController { + struct Constants { + static let backgroundColor: UIColor = UIColor.background + + struct DateLabel { + static let dateFormat: String = "EEEE, d MMM" + } + + struct HeaderLabel { + static let height: CGFloat = 30 + static let horizontalMargin: CGFloat = 20 + } + + struct TableView { + static let marginTop: CGFloat = 10 + static let contentInsetTop: CGFloat = 10 + static let contentInsetLeft: CGFloat = 0 + static let contentInsetBottom: CGFloat = 0 + static let contentInsetRight: CGFloat = 0 + static let headerHeight: CGFloat = 60 + } + } +} diff --git a/Everyday/Modules/Notepad/ResultsScene/Models/ResultsTableViewCellViewModel.swift b/Everyday/Modules/Notepad/ResultsScene/Models/ResultsTableViewCellViewModel.swift new file mode 100644 index 0000000..1e4a011 --- /dev/null +++ b/Everyday/Modules/Notepad/ResultsScene/Models/ResultsTableViewCellViewModel.swift @@ -0,0 +1,45 @@ +// +// ResultsTableViewCellViewModel.swift +// Everyday +// +// Created by user on 02.03.2024. +// + +import UIKit + +struct ResultsTableViewCellViewModel { + let exerciseName: NSAttributedString + let result: NSAttributedString + let minusImage: UIImage? + let plusImage: UIImage? + + init(exercise: Exercise) { + let exerciseNameLabelTitle = exercise.name + let exerciseNameLabelAttributedString = NSAttributedString(string: exerciseNameLabelTitle, attributes: Styles.titleAttributes) + let resultLabelTitle = exercise.result + let resultLabelAttributedString = NSAttributedString(string: resultLabelTitle, attributes: Styles.resultAttributes) + let minusButtonImageName = "minus" + let minusButtonImage = UIImage(systemName: minusButtonImageName) + let plusButtonImageName = "plus" + let plusButtonImage = UIImage(systemName: plusButtonImageName) + + self.exerciseName = exerciseNameLabelAttributedString + self.result = resultLabelAttributedString + self.minusImage = minusButtonImage + self.plusImage = plusButtonImage + } +} + +private extension ResultsTableViewCellViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.primary, + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + + static let resultAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.primary, + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift b/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift index 798fe1c..28a5e81 100644 --- a/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift +++ b/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift @@ -8,28 +8,40 @@ import UIKit struct ResultsViewModel { - let title: NSAttributedString + let resultsTitle: NSAttributedString let restTitle: NSAttributedString let continueTitle: NSAttributedString + let closeImage: UIImage? init() { - let titleLabelTitle = "Результаты" - let titleLabelAttributedString = NSAttributedString(string: titleLabelTitle, attributes: Styles.titleAttributes) + let resultsLabelTitle = "Результаты" + let resultsLabelAttributedString = NSAttributedString(string: resultsLabelTitle, attributes: Styles.titleAttributes) let restButtonTitle = "Отдых" - let restButtonAttributedString = NSAttributedString(string: restButtonTitle, attributes: Styles.titleAttributes) + let restButtonAttributedString = NSAttributedString(string: restButtonTitle, attributes: Styles.buttonTitleAttributes) let continueButtonTitle = "Продолжить" - let continueButtonAttributedString = NSAttributedString(string: continueButtonTitle, attributes: Styles.titleAttributes) + let continueButtonAttributedString = NSAttributedString(string: continueButtonTitle, attributes: Styles.buttonTitleAttributes) + let closeButtonImageName = "xmark.circle.fill" + let closeButtonImage = UIImage(systemName: closeButtonImageName, withConfiguration: Configurations.large) - self.title = titleLabelAttributedString + self.resultsTitle = resultsLabelAttributedString self.restTitle = restButtonAttributedString self.continueTitle = continueButtonAttributedString + self.closeImage = closeButtonImage } } private extension ResultsViewModel { struct Styles { static let titleAttributes: [NSAttributedString.Key: Any] = [ + .font: UIFont.systemFont(ofSize: 24, weight: .regular) + ] + + static let buttonTitleAttributes: [NSAttributedString.Key: Any] = [ .font: UIFont.systemFont(ofSize: 16, weight: .regular) ] } + + struct Configurations { + static let large = UIImage.SymbolConfiguration(textStyle: .largeTitle) + } } diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsProtocols.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsProtocols.swift index f468bcc..36f0e75 100644 --- a/Everyday/Modules/Notepad/ResultsScene/ResultsProtocols.swift +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsProtocols.swift @@ -19,7 +19,6 @@ protocol ResultsModuleOutput: AnyObject { protocol ResultsViewInput: AnyObject { func configure(with viewModel: ResultsViewModel) func reloadData() - func getSelf() -> ResultsViewController } protocol ResultsViewOutput: AnyObject { diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift index cabaac3..fc5a258 100644 --- a/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift @@ -40,9 +40,11 @@ class ResultsTableViewCell: UITableViewCell { // MARK: - Interface - func configure(with exercise: Exercise) { - exerciseNameLabel.text = exercise.name - resultTextField.text = exercise.result + func configure(with viewModel: ResultsTableViewCellViewModel) { + exerciseNameLabel.attributedText = viewModel.exerciseName + resultTextField.attributedText = viewModel.result + minusButton.setImage(viewModel.minusImage, for: .normal) + plusButton.setImage(viewModel.plusImage, for: .normal) } } @@ -52,33 +54,34 @@ private extension ResultsTableViewCell { func layout() { exerciseNameLabel.pin - .left(20) + .left(Constants.horizontalMargin) + .width(Constants.ExerciseNameLabel.width) + .height(Constants.ExerciseNameLabel.height) .vCenter() - .width(200) - .height(40) plusButton.pin + .right(Constants.horizontalMargin) + .width(Constants.Button.width) + .height(Constants.Button.height) .vCenter() - .right(20) - .width(20) - .height(20) resultTextField.pin - .vCenter() .before(of: plusButton) - .width(40) - .height(20) + .width(Constants.ResultTextField.width) + .height(Constants.ResultTextField.height) + .vCenter() minusButton.pin - .vCenter() .before(of: resultTextField) - .width(20) - .height(20) + .width(Constants.Button.width) + .height(Constants.Button.height) + .vCenter() } // MARK: - Setup func setup() { + setupView() setupMinusButton() setupPlusButton() setupResultTextField() @@ -86,20 +89,23 @@ private extension ResultsTableViewCell { contentView.addSubviews(exerciseNameLabel, plusButton, resultTextField, minusButton) } + func setupView() { + contentView.backgroundColor = Constants.backgroundColor + } + func setupMinusButton() { - let minusButtonImage = UIImage(systemName: "minus") - minusButton.setImage(minusButtonImage, for: .normal) + minusButton.tintColor = Constants.Button.tintColor minusButton.addTarget(self, action: #selector(didTapMinusButton), for: .touchUpInside) } func setupPlusButton() { - let plusButtonImage = UIImage(systemName: "plus") - plusButton.setImage(plusButtonImage, for: .normal) + plusButton.tintColor = Constants.Button.tintColor plusButton.addTarget(self, action: #selector(didTapPlusButton), for: .touchUpInside) } func setupResultTextField() { - resultTextField.backgroundColor = .secondaryLabel + resultTextField.backgroundColor = .clear + resultTextField.textColor = Constants.ResultTextField.textColor resultTextField.textAlignment = .center } @@ -129,3 +135,30 @@ private extension ResultsTableViewCell { resultTextField.text = String(result + 1) } } + +// MARK: - Constants + +private extension ResultsTableViewCell { + struct Constants { + static let backgroundColor: UIColor = UIColor.background + + static let horizontalMargin: CGFloat = 20 + + struct ExerciseNameLabel { + static let width: CGFloat = 200 + static let height: CGFloat = 40 + } + + struct ResultTextField { + static let textColor: UIColor = UIColor.Text.primary + static let width: CGFloat = 40 + static let height: CGFloat = 20 + } + + struct Button { + static let tintColor: UIColor = UIColor.Text.primary + static let width: CGFloat = 20 + static let height: CGFloat = 20 + } + } +} diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift index 6401577..32074ec 100644 --- a/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift @@ -61,29 +61,29 @@ private extension ResultsViewController { .all() closeButton.pin - .top(8) - .right(8) - .width(40) - .height(40) + .top(Constants.CloseButton.padding) + .right(Constants.CloseButton.padding) + .width(Constants.CloseButton.width) + .height(Constants.contentHeight) titleLabel.pin .top() - .height(80) + .height(Constants.TitleLabel.height) .left() .right() restButton.pin - .bottom(20) - .height(40) - .left(40) - .width(100) + .bottom(Constants.marginBottom) + .height(Constants.contentHeight) + .left(Constants.horizontalMargin) + .width(Constants.RestButton.width) continueButton.pin - .bottom(20) - .height(40) + .bottom(Constants.marginBottom) + .height(Constants.contentHeight) .after(of: restButton) - .marginLeft(20) - .right(40) + .marginLeft(Constants.ContinueButton.marginLeft) + .right(Constants.horizontalMargin) tableView.pin .below(of: titleLabel) @@ -113,6 +113,7 @@ private extension ResultsViewController { } func setupTableView() { + tableView.backgroundColor = Constants.backgroundColor tableView.delegate = self tableView.dataSource = self tableView.register(ResultsTableViewCell.self, forCellReuseIdentifier: ResultsTableViewCell.reuseID) @@ -125,36 +126,35 @@ private extension ResultsViewController { } func setupContentView() { - contentView.backgroundColor = .white + contentView.backgroundColor = Constants.backgroundColor - let width: CGFloat = view.bounds.width - 24 * 2 + let width: CGFloat = view.bounds.width - Constants.padding * 2 let height: CGFloat = width let x = (view.bounds.width - width) / 2 let y = (view.bounds.height - height) / 2 contentView.frame = CGRect(x: x, y: y, width: width, height: height) - contentView.layer.cornerRadius = 16 + contentView.layer.cornerRadius = Constants.cornerRadius + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) + contentView.addGestureRecognizer(tapGesture) } func setupCloseButton() { - closeButton.setTitle("", for: .normal) - let buttonImageConfiguration = UIImage.SymbolConfiguration(textStyle: .largeTitle) - let buttonImage = UIImage(systemName: "xmark.circle.fill", withConfiguration: buttonImageConfiguration) - closeButton.setImage(buttonImage, for: .normal) closeButton.addTarget(self, action: #selector(didTapCloseButton), for: .touchUpInside) - closeButton.tintColor = .systemMint + closeButton.tintColor = Constants.buttonColor } func setupRestButton() { - restButton.backgroundColor = .systemMint - restButton.layer.cornerRadius = 16 + restButton.backgroundColor = Constants.buttonColor + restButton.layer.cornerRadius = Constants.cornerRadius restButton.addTarget(self, action: #selector(didTapRestButton), for: .touchUpInside) } func setupContinueButton() { - continueButton.backgroundColor = .systemMint - continueButton.layer.cornerRadius = 16 + continueButton.backgroundColor = Constants.buttonColor + continueButton.layer.cornerRadius = Constants.cornerRadius continueButton.addTarget(self, action: #selector(didTapContinueButton), for: .touchUpInside) } @@ -178,6 +178,11 @@ private extension ResultsViewController { func didTapContinueButton() { output.didTapContinueButton() } + + @objc + func dismissKeyboard() { + view.endEditing(true) + } } // MARK: - UITableViewDataSource @@ -193,7 +198,8 @@ extension ResultsViewController: UITableViewDataSource { } let exercise = output.getExercise(at: indexPath.row) - cell.configure(with: exercise) + let viewModel = ResultsTableViewCellViewModel(exercise: exercise) + cell.configure(with: viewModel) return cell } @@ -208,13 +214,10 @@ extension ResultsViewController: UITableViewDelegate { extension ResultsViewController: ResultsViewInput { func configure(with viewModel: ResultsViewModel) { - titleLabel.attributedText = viewModel.title + titleLabel.attributedText = viewModel.resultsTitle restButton.setAttributedTitle(viewModel.restTitle, for: .normal) continueButton.setAttributedTitle(viewModel.continueTitle, for: .normal) - } - - func getSelf() -> ResultsViewController { - return self + closeButton.setImage(viewModel.closeImage, for: .normal) } func reloadData() { @@ -227,3 +230,35 @@ extension ResultsViewController: ResultsViewInput { } } } + +// MARK: - Constants + +private extension ResultsViewController { + struct Constants { + static let backgroundColor: UIColor = UIColor.background + static let buttonColor: UIColor = UIColor.UI.accent + + static let padding: CGFloat = 24 + static let cornerRadius: CGFloat = 16 + static let horizontalMargin: CGFloat = 40 + static let marginBottom: CGFloat = 20 + static let contentHeight: CGFloat = 40 + + struct RestButton { + static let width: CGFloat = 100 + } + + struct ContinueButton { + static let marginLeft: CGFloat = 20 + } + + struct CloseButton { + static let padding: CGFloat = 8 + static let width: CGFloat = 40 + } + + struct TitleLabel { + static let height: CGFloat = 80 + } + } +} diff --git a/Everyday/Modules/Notepad/TimerScene/TimerViewController.swift b/Everyday/Modules/Notepad/TimerScene/TimerViewController.swift index 4afd558..f662b9b 100644 --- a/Everyday/Modules/Notepad/TimerScene/TimerViewController.swift +++ b/Everyday/Modules/Notepad/TimerScene/TimerViewController.swift @@ -55,33 +55,33 @@ private extension TimerViewController { func layout() { remainingTimeLabel.pin .hCenter() - .top(200) - .width(200) - .height(40) + .top(Constants.RemainingTimeLabel.marginTop) + .height(Constants.contentHeight) + .width(Constants.contentWidth) startButton.pin .below(of: remainingTimeLabel) .hCenter() - .height(40) - .width(100) + .height(Constants.contentHeight) + .width(Constants.contentWidth) stopButton.pin .below(of: startButton) .hCenter() - .height(40) - .width(100) + .height(Constants.contentHeight) + .width(Constants.contentWidth) resetButton.pin .below(of: stopButton) .hCenter() - .height(40) - .width(100) + .height(Constants.contentHeight) + .width(Constants.contentWidth) skipButton.pin .below(of: resetButton) .hCenter() - .height(40) - .width(200) + .height(Constants.contentHeight) + .width(Constants.contentWidth) } // MARK: - Setup @@ -98,31 +98,30 @@ private extension TimerViewController { } func setupView() { - view.backgroundColor = .systemBackground + view.backgroundColor = Constants.backgroundColor } func setupStartButton() { - startButton.backgroundColor = .systemMint + startButton.backgroundColor = Constants.Button.backgroundColor startButton.addTarget(self, action: #selector(didTapStartButton), for: .touchUpInside) } func setupStopButton() { - stopButton.backgroundColor = .systemMint + stopButton.backgroundColor = Constants.Button.backgroundColor stopButton.addTarget(self, action: #selector(didTapStopButton), for: .touchUpInside) } func setupResetButton() { - resetButton.backgroundColor = .systemMint + resetButton.backgroundColor = Constants.Button.backgroundColor resetButton.addTarget(self, action: #selector(didTapResetButton), for: .touchUpInside) } func setupSkipButton() { - skipButton.backgroundColor = .systemMint + skipButton.backgroundColor = Constants.Button.backgroundColor skipButton.addTarget(self, action: #selector(didTapSkipButton), for: .touchUpInside) } func setupRemainingTimeLabel() { - remainingTimeLabel.font = UIFont.systemFont(ofSize: 24, weight: .bold) remainingTimeLabel.textAlignment = .center } @@ -164,3 +163,22 @@ extension TimerViewController: TimerViewInput { remainingTimeLabel.text = String(time) } } + +// MARK: - Constants + +private extension TimerViewController { + struct Constants { + static let backgroundColor: UIColor = UIColor.background + + static let contentWidth: CGFloat = 100 + static let contentHeight: CGFloat = 100 + + struct Button { + static let backgroundColor: UIColor = UIColor.UI.accent + } + + struct RemainingTimeLabel { + static let marginTop: CGFloat = 200 + } + } +} diff --git a/Everyday/Modules/Notepad/TrainingScene/Models/TrainingTableViewCellViewModel.swift b/Everyday/Modules/Notepad/TrainingScene/Models/TrainingTableViewCellViewModel.swift new file mode 100644 index 0000000..79092ec --- /dev/null +++ b/Everyday/Modules/Notepad/TrainingScene/Models/TrainingTableViewCellViewModel.swift @@ -0,0 +1,41 @@ +// +// TrainingTableViewCellViewModel.swift +// Everyday +// +// Created by user on 02.03.2024. +// + +import UIKit + +struct TrainingTableViewCellViewModel { + let title: NSAttributedString + let result: NSAttributedString + let startTitle: NSAttributedString + + init(exercise: Exercise) { + let titleLabelTitle = exercise.name + let titleLabelAttributedString = NSAttributedString(string: titleLabelTitle, attributes: Styles.titleAttributes) + let resultLabelTitle = exercise.result + let resultLabelAttributedString = NSAttributedString(string: resultLabelTitle, attributes: Styles.resultAttributes) + let startButtonTitle = "Начать" + let startButtonAttributedString = NSAttributedString(string: startButtonTitle, attributes: Styles.titleAttributes) + + self.title = titleLabelAttributedString + self.result = resultLabelAttributedString + self.startTitle = startButtonAttributedString + } +} + +private extension TrainingTableViewCellViewModel { + struct Styles { + static let titleAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.primary, + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + + static let resultAttributes: [NSAttributedString.Key: Any] = [ + .foregroundColor: UIColor.Text.primary, + .font: UIFont.systemFont(ofSize: 16, weight: .regular) + ] + } +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift index c5f8597..f02a24f 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift @@ -49,9 +49,11 @@ class TrainingTableViewCell: UITableViewCell { // MARK: - Interface - func configure(with exercise: Exercise, and index: Int) { - exerciseNameLabel.text = exercise.name - resultLabel.text = exercise.result + func configure(with viewModel: TrainingTableViewCellViewModel, and index: Int) { + exerciseNameLabel.attributedText = viewModel.title + resultLabel.attributedText = viewModel.result + startButton.setAttributedTitle(viewModel.startTitle, for: .normal) + startButton.tag = index } @@ -98,30 +100,30 @@ private extension TrainingTableViewCell { func layout() { checkbox.pin - .left(20) + .left(Constants.horizontalMargin) + .width(Constants.Checkbox.width) + .height(Constants.contentHeight) .vCenter() - .width(40) - .height(40) exerciseNameLabel.pin .after(of: checkbox) - .marginLeft(20) - .width(200) - .height(40) + .marginLeft(Constants.horizontalMargin) + .width(Constants.ExerciseNameLabel.width) + .height(Constants.contentHeight) .vCenter() resultLabel.pin .right() .after(of: exerciseNameLabel) - .marginLeft(20) - .height(40) + .marginLeft(Constants.horizontalMargin) + .height(Constants.contentHeight) .vCenter() startButton.pin - .right(20) + .right(Constants.horizontalMargin) .after(of: exerciseNameLabel) - .marginLeft(20) - .height(40) + .marginLeft(Constants.horizontalMargin) + .height(Constants.contentHeight) .vCenter() } @@ -132,9 +134,8 @@ private extension TrainingTableViewCell { checkbox.stateChangeAnimation = .bounce(.fill) checkbox.setCheckState(.unchecked, animated: true) - startButton.setTitle("Начать", for: .normal) - startButton.backgroundColor = .systemMint - startButton.layer.cornerRadius = 16 + startButton.backgroundColor = Constants.StartButton.backgroundColor + startButton.layer.cornerRadius = Constants.StartButton.cornerRadius startButton.isHidden = true contentView.addSubviews(checkbox, exerciseNameLabel, resultLabel, startButton) @@ -156,3 +157,27 @@ private extension TrainingTableViewCell { delegate?.switchCell(self, with: value) } } + +// MARK: - Constants + +private extension TrainingTableViewCell { + struct Constants { + static let backgroundColor: UIColor = UIColor.background + + static let horizontalMargin: CGFloat = 20 + static let contentHeight: CGFloat = 40 + + struct Checkbox { + static let width: CGFloat = 40 + } + + struct ExerciseNameLabel { + static let width: CGFloat = 200 + } + + struct StartButton { + static let backgroundColor: UIColor = UIColor.UI.accent + static let cornerRadius: CGFloat = 16 + } + } +} diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift index 2b5c308..b85dfdc 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift @@ -51,13 +51,13 @@ private extension TrainingViewController { func layout() { finishButton.pin .top(view.pin.safeArea) - .marginTop(40) - .horizontally(20) - .height(30) + .marginTop(Constants.FinishButton.marginTop) + .horizontally(Constants.FinishButton.horizontalMargin) + .height(Constants.FinishButton.height) tableView.pin .below(of: finishButton) - .marginTop(170) + .marginTop(Constants.TableView.marginTop) .horizontally() .bottom() } @@ -73,18 +73,19 @@ private extension TrainingViewController { } func setupView() { - view.backgroundColor = .systemBackground + view.backgroundColor = Constants.backgroundColor } func setupTableView() { + tableView.backgroundColor = Constants.backgroundColor tableView.delegate = self tableView.dataSource = self tableView.register(TrainingTableViewCell.self, forCellReuseIdentifier: TrainingTableViewCell.reuseID) - tableView.rowHeight = 80 + tableView.rowHeight = Constants.TableView.rowHeight } func setupFinishButton() { - finishButton.backgroundColor = .systemMint + finishButton.backgroundColor = Constants.FinishButton.backgroundColor finishButton.addTarget(self, action: #selector(didTapFinishButton), for: .touchUpInside) finishButton.isHidden = true } @@ -114,7 +115,10 @@ extension TrainingViewController: UITableViewDataSource { return UITableViewCell() } - cell.configure(with: output.getExercise(at: indexPath.row), and: indexPath.row) + let exercise = output.getExercise(at: indexPath.row) + let viewModel = TrainingTableViewCellViewModel(exercise: exercise) + + cell.configure(with: viewModel, and: indexPath.row) cell.addStartButtonTarget(self, action: #selector(didTapStartButton)) cell.delegate = self @@ -173,3 +177,24 @@ extension TrainingViewController: TrainingViewInput { } } } + +// MARK: - Constants + +private extension TrainingViewController { + struct Constants { + static let backgroundColor: UIColor = UIColor.background + + struct FinishButton { + static let backgroundColor: UIColor = UIColor.UI.accent + + static let height: CGFloat = 30 + static let marginTop: CGFloat = 40 + static let horizontalMargin: CGFloat = 20 + } + + struct TableView { + static let marginTop: CGFloat = 170 + static let rowHeight: CGFloat = 80 + } + } +} From fd5b6c24d4a203be36fc0f72409f3ff25049b4f3 Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Sat, 2 Mar 2024 21:29:46 +0300 Subject: [PATCH 06/13] loading view --- .../NotepadScene/NotepadInteractor.swift | 4 ++++ .../NotepadScene/NotepadPresenter.swift | 9 ++++++++- .../NotepadScene/NotepadProtocols.swift | 4 ++++ .../NotepadScene/NotepadViewController.swift | 19 ++++++++++++++++++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift index 8d29483..2bd3308 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadInteractor.swift @@ -20,6 +20,8 @@ final class NotepadInteractor { extension NotepadInteractor: NotepadInteractorInput { func loadResult(date: Date) { + self.output?.didStartLoading() + dayManager.getDayResults(on: date) { [weak self] result in guard let self else { return @@ -27,6 +29,7 @@ extension NotepadInteractor: NotepadInteractorInput { switch result { case .success(let workoutDays): + self.output?.didEndLoading() self.output?.didLoadDay(with: workoutDays, true) case .failure: self.loadSchedule() @@ -39,6 +42,7 @@ extension NotepadInteractor: NotepadInteractorInput { guard let self else { return } + self.output?.didEndLoading() switch result { case .success(let workoutDays): diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadPresenter.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadPresenter.swift index 046cf85..7845317 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadPresenter.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadPresenter.swift @@ -76,7 +76,6 @@ extension NotepadPresenter: NotepadViewOutput { } extension NotepadPresenter: NotepadInteractorOutput { - func didLoadDay(with workoutDays: [(workout: Workout, indexOfDay: Int)], _ isResult: Bool) { self.workoutDays = workoutDays self.isResult = isResult @@ -85,4 +84,12 @@ extension NotepadPresenter: NotepadInteractorOutput { view?.configure(with: viewModel) view?.reloadData() } + + func didStartLoading() { + view?.showLoadingView() + } + + func didEndLoading() { + view?.dismissLoadingView() + } } diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadProtocols.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadProtocols.swift index 392bd0d..becd056 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadProtocols.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadProtocols.swift @@ -18,6 +18,8 @@ protocol NotepadModuleOutput: AnyObject { protocol NotepadViewInput: AnyObject { func configure(with viewModel: NotepadViewModel) func reloadData() + func showLoadingView() + func dismissLoadingView() } protocol NotepadViewOutput: AnyObject { @@ -40,6 +42,8 @@ protocol NotepadInteractorInput: AnyObject { protocol NotepadInteractorOutput: AnyObject { func didLoadDay(with workoutDays: [(workout: Workout, indexOfDay: Int)], _ isResult: Bool) + func didStartLoading() + func didEndLoading() } protocol NotepadRouterInput: AnyObject { diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift index f6d8d50..5f115e2 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift @@ -17,6 +17,7 @@ final class NotepadViewController: UIViewController { private let stateLabel = UILabel() private let tableView = UITableView(frame: .zero, style: .insetGrouped) + private let activityIndicator = UIActivityIndicatorView(style: .large) // MARK: - Init @@ -36,8 +37,8 @@ final class NotepadViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - output.didLoadView() setup() + output.didLoadView() } override func viewDidLayoutSubviews() { @@ -189,6 +190,22 @@ extension NotepadViewController: NotepadViewInput { self.tableView.reloadData() } } + + func showLoadingView() { + view.addSubview(activityIndicator) + + activityIndicator.pin + .hCenter() + .vCenter() + + activityIndicator.startAnimating() + } + + func dismissLoadingView() { + DispatchQueue.main.async { + self.activityIndicator.removeFromSuperview() + } + } } // MARK: - Constants From d34ffef8d02d5d5338de60e5e675f966b2c3a44d Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Sat, 2 Mar 2024 21:39:50 +0300 Subject: [PATCH 07/13] finish set logic change --- .../Modules/Notepad/TrainingScene/TrainingPresenter.swift | 6 +++--- .../Notepad/TrainingScene/TrainingViewController.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift index 1f252b3..5461841 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingPresenter.swift @@ -49,9 +49,9 @@ extension TrainingPresenter: TrainingViewOutput { switchStates[index] = value let allSatisfy = switchStates.allSatisfy { $0 } if allSatisfy { - view?.showFinishButton() +// view?.showFinishButton() } else { - view?.hideFinishButton() +// view?.hideFinishButton() } } @@ -103,7 +103,7 @@ extension TrainingPresenter: ResultsModuleOutput { } switchStates = [Bool](repeating: false, count: workoutDay.workout.days[workoutDay.indexOfDay].sets[indexOfSet].exercises.count) - view?.hideFinishButton() +// view?.hideFinishButton() view?.reloadData() } } diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift index b85dfdc..39b293f 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift @@ -86,8 +86,8 @@ private extension TrainingViewController { func setupFinishButton() { finishButton.backgroundColor = Constants.FinishButton.backgroundColor + finishButton.layer.cornerRadius = Constants.FinishButton.cornerRadius finishButton.addTarget(self, action: #selector(didTapFinishButton), for: .touchUpInside) - finishButton.isHidden = true } // MARK: - Actions @@ -186,7 +186,7 @@ private extension TrainingViewController { struct FinishButton { static let backgroundColor: UIColor = UIColor.UI.accent - + static let cornerRadius: CGFloat = 16 static let height: CGFloat = 30 static let marginTop: CGFloat = 40 static let horizontalMargin: CGFloat = 20 From 2d691515fe771fa7e9f01ba39cd41f683f999f55 Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Mon, 4 Mar 2024 22:17:50 +0300 Subject: [PATCH 08/13] vkid+scene delegate --- .../OnBoarding/ContentView.swift | 4 +- .../ProfileAcknowledgementView.swift | 426 +++++++++--------- .../SignUp/SignUpInteractor.swift | 20 +- .../SignUp/SignUpPresenter.swift | 20 +- .../SignUp/SignUpProtocols.swift | 2 +- .../TrainingScene/TrainingTableViewCell.swift | 2 + Everyday/Services/Auth/AuthService.swift | 21 +- .../Auth/VKIDAuth/VKIDAuthService.swift | 122 ++--- Everyday/Support/AppDelegate.swift | 6 +- Everyday/Support/SceneDelegate.swift | 62 ++- 10 files changed, 366 insertions(+), 319 deletions(-) diff --git a/Everyday/Modules/Authorization/OnBoarding/ContentView.swift b/Everyday/Modules/Authorization/OnBoarding/ContentView.swift index f5ac98d..2e0549a 100644 --- a/Everyday/Modules/Authorization/OnBoarding/ContentView.swift +++ b/Everyday/Modules/Authorization/OnBoarding/ContentView.swift @@ -52,8 +52,8 @@ struct ContentView: View { }) .tag(6) -// ProfileAcknowledgementView(onFinish: onFinish) -// .tag(7) + ProfileAcknowledgementView(onFinish: onFinish) + .tag(7) } .animation(.easeInOut, value: pageIndex) .indexViewStyle(.page(backgroundDisplayMode: .interactive)) diff --git a/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift b/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift index 537dce3..fb70067 100644 --- a/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift +++ b/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift @@ -1,215 +1,215 @@ -// import SwiftUI -// -// struct ProfileAcknowledgementView: View { -// -// // MARK: - properties -// -// @StateObject private var viewModel = ProfileAcknowledgementViewModel() -// @State private var controller: ProfileAcknowledgementController? -// -// @State private var selectedAge: Age = .small -// @State private var selectedGender: Gender = .male -// @State private var selectedWeight = "" -// @State private var selectedName = "" -// @State private var selectedSurname = "" -// @State private var selectedNickname = "" -// -// private let defaultImage = Image("anonymous") -// -// var onFinish: (() -> Void)? -// -// // MARK: - body -// -// var body: some View { -// ScrollView { -// VStack(spacing: Constants.VStackValues.spacing) { -// Spacer() -// -// Text(AttributedString(viewModel.title)) -// .font(.headline) -// .multilineTextAlignment(.center) -// .foregroundColor(Constants.primaryText) -// -// Spacer() -// -// ZStack { -//// if let inputImage = viewModel.inputImage { -//// Image(uiImage: inputImage) -//// .resizable() -//// .scaledToFill() -//// } else { -// defaultImage + import SwiftUI + + struct ProfileAcknowledgementView: View { + + // MARK: - properties + + @StateObject private var viewModel = ProfileAcknowledgementViewModel() + @State private var controller: ProfileAcknowledgementController? + + @State private var selectedAge: Age = .small + @State private var selectedGender: Gender = .male + @State private var selectedWeight = "" + @State private var selectedName = "" + @State private var selectedSurname = "" + @State private var selectedNickname = "" + + private let defaultImage = Image("anonymous") + + var onFinish: (() -> Void)? + + // MARK: - body + + var body: some View { + ScrollView { + VStack(spacing: Constants.VStackValues.spacing) { + Spacer() + + Text(AttributedString(viewModel.title)) + .font(.headline) + .multilineTextAlignment(.center) + .foregroundColor(Constants.primaryText) + + Spacer() + + ZStack { +// if let inputImage = viewModel.inputImage { +// Image(uiImage: inputImage) // .resizable() // .scaledToFill() -//// } -// } -// .frame(width: Constants.ZStackValues.size.width, height: Constants.ZStackValues.size.height) -// .clipShape(Circle()) -// .overlay(Circle().stroke(Color.primary, lineWidth: Constants.ZStackValues.overlay)) -// .padding() -// -// Button(action: { -// viewModel.showingImagePicker = true -// }, label: { -// Text(AttributedString(viewModel.photoTitle)) -// .foregroundColor(Constants.primaryText) -// }) -// -// Spacer() -// -// UserTextField(text: $selectedName, keyType: .default, placeholder: viewModel.name) -// .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) -// .padding(.horizontal, Constants.TextFieldValues.hPadding) -// .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) -// .cornerRadius(Constants.TextFieldValues.cornerRadius) -// -// UserTextField(text: $selectedSurname, keyType: .default, placeholder: viewModel.surname) -// .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) -// .padding(.horizontal, Constants.TextFieldValues.hPadding) -// .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) -// .cornerRadius(Constants.TextFieldValues.cornerRadius) -// -// UserTextField(text: $selectedNickname, keyType: .default, placeholder: viewModel.nickname) -// .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) -// .padding(.horizontal, Constants.TextFieldValues.hPadding) -// .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) -// .cornerRadius(Constants.TextFieldValues.cornerRadius) -// -// Spacer() -// -// Text(AttributedString(viewModel.ageConfirm)) -// .font(.headline) -// .multilineTextAlignment(.center) -// .foregroundColor(Color.primaryText) -// -// ForEach(controller?.ages ?? [], id: \.self) { age in -// let ageText = viewModel.ageText(for: age) -// AgeButtonView(age: age, ageText: ageText, selectedAge: $selectedAge ) -// } -// -// Spacer() -// -// Text(AttributedString(viewModel.genderConfirm)) -// .font(.subheadline) -// .multilineTextAlignment(.center) -// .foregroundColor(Constants.primaryText) -// -// ForEach(viewModel.gendersUI, id: \.gender) { genderUI in -// GenderButtonView( -// gender: genderUI.gender, -// imageName: genderUI.imageName, -// localizedText: genderUI.localizedText, -// selectedGender: $selectedGender -// ) -// } -// -// Spacer() -// -// Text(AttributedString(viewModel.weightConfirm)) -// .font(.headline) -// .multilineTextAlignment(.center) -// .foregroundColor(Color.primaryText) -// -// DecimalTextField(text: $selectedWeight, keyType: .numberPad, placeholder: viewModel.placeholder) -// .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) -// .padding(.horizontal, Constants.TextFieldValues.hPadding) -// .background(Color.gray.opacity(Constants.TextFieldValues.colorOpacity)) -// .cornerRadius(Constants.TextFieldValues.cornerRadius) -// -// Spacer() -// -// Button(action: { -// -// saveDataToModel() -// -// AuthService.shared.authWithFirebase(with: ProfileAcknowledgementModel.shared) -// -// onFinish?() -// }, label: { -// Text(AttributedString(viewModel.starter)) -// .padding(.horizontal, Constants.ButtonValues.hPadding) -// .padding(.vertical, Constants.ButtonValues.vPadding) -// .frame(maxWidth: .infinity) -// .background(Constants.accent) -// .foregroundColor(Constants.button) -// .cornerRadius(Constants.ButtonValues.cornerRadius) -// }) -// -// .padding(.bottom, Constants.VStackValues.bPadding) -// } -// .padding(.horizontal) -// .sheet(isPresented: $viewModel.showingImagePicker, onDismiss: viewModel.loadImage) { -// ImagePicker(image: self.$viewModel.inputImage) -// } -// } -// .scrollIndicators(.hidden) -// .onAppear { -// let ageEnum = Age.from(description: ProfileAcknowledgementModel.shared.age ?? "") ?? .small -// let genderEnum = Gender.from(description: ProfileAcknowledgementModel.shared.gender ?? "") ?? .male -// let weight = ProfileAcknowledgementModel.shared.weight -// let name = ProfileAcknowledgementModel.shared.firstname -// let surname = ProfileAcknowledgementModel.shared.lastname -// let nickname = ProfileAcknowledgementModel.shared.nickname -// -// self.controller = ProfileAcknowledgementController(ageDescription: ageEnum.description, -// genderDescription: genderEnum.description, -// weight: weight, -// name: name, -// surname: surname, -// nickname: nickname) -// -// self.selectedAge = controller?.selectedAge ?? .small -// self.selectedGender = controller?.selectedGender ?? .male -// self.selectedWeight = controller?.weight ?? "0" -// self.selectedName = controller?.name ?? "" -// self.selectedSurname = controller?.surname ?? "" -// self.selectedNickname = controller?.nickname ?? "" -// } -// } -// -// func saveDataToModel() { -// ProfileAcknowledgementModel.shared.firstname = selectedName -// ProfileAcknowledgementModel.shared.lastname = selectedSurname -// ProfileAcknowledgementModel.shared.nickname = selectedNickname -// ProfileAcknowledgementModel.shared.profileImage = viewModel.inputImage -// ProfileAcknowledgementModel.shared.age = selectedAge.description -// ProfileAcknowledgementModel.shared.gender = selectedGender.description -// ProfileAcknowledgementModel.shared.weight = selectedWeight -// } -// } -// -// // MARK: - extensions -// -// private extension ProfileAcknowledgementView { -// struct Constants { -// -// static let primaryText = Color.primaryText -// static let accent = Color.accent -// static let clear = Color.clear -// static let gray = Color.gray -// static let button = Color.grayElement -// -// struct VStackValues { -// static let spacing: CGFloat = 15 -// static let bPadding: CGFloat = 65 -// } -// -// struct ZStackValues { -// static let size: CGSize = CGSize(width: 150, height: 150) -// static let overlay: CGFloat = 0.5 -// } -// -// struct ButtonValues { -// static let hPadding: CGFloat = 100 -// static let vPadding: CGFloat = 16 -// static let cornerRadius: CGFloat = 20 -// } -// -// struct TextFieldValues { -// static let size: CGSize = CGSize(width: 300, height: 50) -// static let hPadding: CGFloat = 24 -// static let cornerRadius: CGFloat = 8 -// static let colorOpacity: CGFloat = 0.1 -// } -// } -// } +// } else { + defaultImage + .resizable() + .scaledToFill() +// } + } + .frame(width: Constants.ZStackValues.size.width, height: Constants.ZStackValues.size.height) + .clipShape(Circle()) + .overlay(Circle().stroke(Color.primary, lineWidth: Constants.ZStackValues.overlay)) + .padding() + + Button(action: { + viewModel.showingImagePicker = true + }, label: { + Text(AttributedString(viewModel.photoTitle)) + .foregroundColor(Constants.primaryText) + }) + + Spacer() + + UserTextField(text: $selectedName, keyType: .default, placeholder: viewModel.name) + .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) + .padding(.horizontal, Constants.TextFieldValues.hPadding) + .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) + .cornerRadius(Constants.TextFieldValues.cornerRadius) + + UserTextField(text: $selectedSurname, keyType: .default, placeholder: viewModel.surname) + .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) + .padding(.horizontal, Constants.TextFieldValues.hPadding) + .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) + .cornerRadius(Constants.TextFieldValues.cornerRadius) + + UserTextField(text: $selectedNickname, keyType: .default, placeholder: viewModel.nickname) + .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) + .padding(.horizontal, Constants.TextFieldValues.hPadding) + .background(Constants.gray.opacity(Constants.TextFieldValues.colorOpacity)) + .cornerRadius(Constants.TextFieldValues.cornerRadius) + + Spacer() + + Text(AttributedString(viewModel.ageConfirm)) + .font(.headline) + .multilineTextAlignment(.center) + .foregroundColor(Color.primaryText) + + ForEach(controller?.ages ?? [], id: \.self) { age in + let ageText = viewModel.ageText(for: age) + AgeButtonView(age: age, ageText: ageText, selectedAge: $selectedAge ) + } + + Spacer() + + Text(AttributedString(viewModel.genderConfirm)) + .font(.subheadline) + .multilineTextAlignment(.center) + .foregroundColor(Constants.primaryText) + + ForEach(viewModel.gendersUI, id: \.gender) { genderUI in + GenderButtonView( + gender: genderUI.gender, + imageName: genderUI.imageName, + localizedText: genderUI.localizedText, + selectedGender: $selectedGender + ) + } + + Spacer() + + Text(AttributedString(viewModel.weightConfirm)) + .font(.headline) + .multilineTextAlignment(.center) + .foregroundColor(Color.primaryText) + + DecimalTextField(text: $selectedWeight, keyType: .numberPad, placeholder: viewModel.placeholder) + .frame(width: Constants.TextFieldValues.size.width, height: Constants.TextFieldValues.size.height) + .padding(.horizontal, Constants.TextFieldValues.hPadding) + .background(Color.gray.opacity(Constants.TextFieldValues.colorOpacity)) + .cornerRadius(Constants.TextFieldValues.cornerRadius) + + Spacer() + + Button(action: { + + saveDataToModel() + + AuthService.shared.authWithFirebase(with: ProfileAcknowledgementModel.shared) + + onFinish?() + }, label: { + Text(AttributedString(viewModel.starter)) + .padding(.horizontal, Constants.ButtonValues.hPadding) + .padding(.vertical, Constants.ButtonValues.vPadding) + .frame(maxWidth: .infinity) + .background(Constants.accent) + .foregroundColor(Constants.button) + .cornerRadius(Constants.ButtonValues.cornerRadius) + }) + + .padding(.bottom, Constants.VStackValues.bPadding) + } + .padding(.horizontal) + .sheet(isPresented: $viewModel.showingImagePicker, onDismiss: viewModel.loadImage) { + ImagePicker(image: self.$viewModel.inputImage) + } + } + .scrollIndicators(.hidden) + .onAppear { + let ageEnum = Age.from(description: ProfileAcknowledgementModel.shared.age ?? "") ?? .small + let genderEnum = Gender.from(description: ProfileAcknowledgementModel.shared.gender ?? "") ?? .male + let weight = ProfileAcknowledgementModel.shared.weight + let name = ProfileAcknowledgementModel.shared.firstname + let surname = ProfileAcknowledgementModel.shared.lastname + let nickname = ProfileAcknowledgementModel.shared.nickname + + self.controller = ProfileAcknowledgementController(ageDescription: ageEnum.description, + genderDescription: genderEnum.description, + weight: weight, + name: name, + surname: surname, + nickname: nickname) + + self.selectedAge = controller?.selectedAge ?? .small + self.selectedGender = controller?.selectedGender ?? .male + self.selectedWeight = controller?.weight ?? "0" + self.selectedName = controller?.name ?? "" + self.selectedSurname = controller?.surname ?? "" + self.selectedNickname = controller?.nickname ?? "" + } + } + + func saveDataToModel() { + ProfileAcknowledgementModel.shared.firstname = selectedName + ProfileAcknowledgementModel.shared.lastname = selectedSurname + ProfileAcknowledgementModel.shared.nickname = selectedNickname + ProfileAcknowledgementModel.shared.profileImage = viewModel.inputImage + ProfileAcknowledgementModel.shared.age = selectedAge.description + ProfileAcknowledgementModel.shared.gender = selectedGender.description + ProfileAcknowledgementModel.shared.weight = selectedWeight + } + } + + // MARK: - extensions + + private extension ProfileAcknowledgementView { + struct Constants { + + static let primaryText = Color.primaryText + static let accent = Color.accent + static let clear = Color.clear + static let gray = Color.gray + static let button = Color.grayElement + + struct VStackValues { + static let spacing: CGFloat = 15 + static let bPadding: CGFloat = 65 + } + + struct ZStackValues { + static let size: CGSize = CGSize(width: 150, height: 150) + static let overlay: CGFloat = 0.5 + } + + struct ButtonValues { + static let hPadding: CGFloat = 100 + static let vPadding: CGFloat = 16 + static let cornerRadius: CGFloat = 20 + } + + struct TextFieldValues { + static let size: CGSize = CGSize(width: 300, height: 50) + static let hPadding: CGFloat = 24 + static let cornerRadius: CGFloat = 8 + static let colorOpacity: CGFloat = 0.1 + } + } + } diff --git a/Everyday/Modules/Authorization/SignUp/SignUpInteractor.swift b/Everyday/Modules/Authorization/SignUp/SignUpInteractor.swift index 81ac288..654695d 100644 --- a/Everyday/Modules/Authorization/SignUp/SignUpInteractor.swift +++ b/Everyday/Modules/Authorization/SignUp/SignUpInteractor.swift @@ -19,16 +19,16 @@ final class SignUpInteractor { } extension SignUpInteractor: SignUpInteractorInput { -// func authWithVKID(completion: @escaping (Result) -> Void) { -// guard let viewController = self.viewController else { -// completion(.failure(NSError(domain: "AuthError", code: 0, userInfo: [NSLocalizedDescriptionKey: "ViewController is nil"]))) -// return -// } -// -// authService.authWithVKID(with: viewController) { result in -// completion(result) -// } -// } + func authWithVKID(completion: @escaping (Result) -> Void) { + guard let viewController = self.viewController else { + completion(.failure(NSError(domain: "AuthError", code: 0, userInfo: [NSLocalizedDescriptionKey: "ViewController is nil"]))) + return + } + + authService.authWithVKID(with: viewController) { result in + completion(result) + } + } func authWithGoogle(completion: @escaping (Result) -> Void) { guard let viewController = self.viewController else { diff --git a/Everyday/Modules/Authorization/SignUp/SignUpPresenter.swift b/Everyday/Modules/Authorization/SignUp/SignUpPresenter.swift index 6454855..0b986c7 100644 --- a/Everyday/Modules/Authorization/SignUp/SignUpPresenter.swift +++ b/Everyday/Modules/Authorization/SignUp/SignUpPresenter.swift @@ -63,16 +63,16 @@ extension SignUpPresenter: SignUpViewOutput { func didTapSignWithVKButton() { AuthModel.shared.whichSign = .vk -// interactor.authWithVKID { result in -// DispatchQueue.main.async { -// switch result { -// case .success: -// self.router.openOnBoarding() -// case .failure(let error): -// self.view?.showAlert(with: "network", message: NSMutableAttributedString(string: error.localizedDescription)) -// } -// } -// } + interactor.authWithVKID { result in + DispatchQueue.main.async { + switch result { + case .success: + self.router.openOnBoarding() + case .failure(let error): + self.view?.showAlert(with: "network", message: NSMutableAttributedString(string: error.localizedDescription)) + } + } + } } func didTapSignWithGoogleButton() { diff --git a/Everyday/Modules/Authorization/SignUp/SignUpProtocols.swift b/Everyday/Modules/Authorization/SignUp/SignUpProtocols.swift index af62b67..69e7771 100644 --- a/Everyday/Modules/Authorization/SignUp/SignUpProtocols.swift +++ b/Everyday/Modules/Authorization/SignUp/SignUpProtocols.swift @@ -30,7 +30,7 @@ protocol SignUpViewOutput: AnyObject { protocol SignUpInteractorInput: AnyObject { func authWithGoogle(completion: @escaping (Result) -> Void) -// func authWithVKID(completion: @escaping (Result) -> Void) + func authWithVKID(completion: @escaping (Result) -> Void) } protocol SignUpInteractorOutput: AnyObject { diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift index f02a24f..6b45f7c 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingTableViewCell.swift @@ -132,6 +132,7 @@ private extension TrainingTableViewCell { func setup() { checkbox.addTarget(self, action: #selector(switchValueChanged), for: .valueChanged) checkbox.stateChangeAnimation = .bounce(.fill) + checkbox.tintColor = Constants.Checkbox.tintColor checkbox.setCheckState(.unchecked, animated: true) startButton.backgroundColor = Constants.StartButton.backgroundColor @@ -168,6 +169,7 @@ private extension TrainingTableViewCell { static let contentHeight: CGFloat = 40 struct Checkbox { + static let tintColor: UIColor = UIColor.UI.accent static let width: CGFloat = 40 } diff --git a/Everyday/Services/Auth/AuthService.swift b/Everyday/Services/Auth/AuthService.swift index cd15256..6be3962 100644 --- a/Everyday/Services/Auth/AuthService.swift +++ b/Everyday/Services/Auth/AuthService.swift @@ -8,7 +8,7 @@ import UIKit protocol AuthServiceDescription { -// func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) + func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) func authWithGoogle(with presentingController: UIViewController, completion: @escaping (Result) -> Void) func authWithFirebase(with userRequest: ProfileAcknowledgementModel) } @@ -16,22 +16,23 @@ protocol AuthServiceDescription { final class AuthService: AuthServiceDescription { static let shared = AuthService() -// private let vkidAuthService: VKIDAuthServiceDescription + private let vkidAuthService: VKIDAuthServiceDescription private let googleAuthService: GoogleAuthServiceDescription private let firebaseAuthService: FirebaseAuthServiceDescription - private init(googleAuthService: GoogleAuthServiceDescription = GoogleAuthService.shared, - firebaseAuthService: FirebaseAuthServiceDescription = FirebaseAuthService.shared ) { -// self.vkidAuthService = vkidAuthService + private init(vkidAuthService: VKIDAuthServiceDescription = VKIDAuthService.shared, + googleAuthService: GoogleAuthServiceDescription = GoogleAuthService.shared, + firebaseAuthService: FirebaseAuthServiceDescription = FirebaseAuthService.shared) { + self.vkidAuthService = vkidAuthService self.googleAuthService = googleAuthService self.firebaseAuthService = firebaseAuthService } -// func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { -// vkidAuthService.authWithVKID(with: presentingController) { result in -// completion(result) -// } -// } + func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { + vkidAuthService.authWithVKID(with: presentingController) { result in + completion(result) + } + } func authWithGoogle(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { googleAuthService.authWithGoogle(with: presentingController) { result in diff --git a/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift b/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift index 0108167..1d5eaae 100644 --- a/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift +++ b/Everyday/Services/Auth/VKIDAuth/VKIDAuthService.swift @@ -6,64 +6,64 @@ // import UIKit -// import VKID -// -// protocol VKIDAuthServiceDescription { -// var vkid: VKID? { get } -// func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) -// } -// -// final class VKIDAuthService: VKIDAuthServiceDescription { -// static let shared = VKIDAuthService() -// -// var vkid: VKID? -// -// private init() { -// guard -// let clientId = InfoPlist.vkClientId, !clientId.isEmpty, -// let clientSecret = InfoPlist.vkClientSecret, !clientSecret.isEmpty -// else { -// preconditionFailure("Info.plist does not contain correct values for CLIENT_ID and CLIENT_SECRET keys") -// } -// -// do { -// let vkid = try VKID( -// config: Configuration( -// appCredentials: AppCredentials( -// clientId: clientId, -// clientSecret: clientSecret -// ) -// ) -// ) -// self.vkid = vkid -// } catch { -// preconditionFailure("Failed to initialize VKID: \(error)") -// } -// } -// -// func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { -// vkid?.authorize( -// using: .uiViewController(presentingController) -// ) { result in -// do { -// let session = try result.get() -// let passwordGenerator = PasswordGenerator(length: 20) -// -// ProfileAcknowledgementModel.shared.firstname = session.user.firstName -// ProfileAcknowledgementModel.shared.lastname = session.user.lastName -// ProfileAcknowledgementModel.shared.email = session.user.email -// ProfileAcknowledgementModel.shared.password = passwordGenerator.generatePassword() -// // session.user.avatarURL -// -// completion(.success(())) -// } catch AuthError.cancelled { -// print("Auth cancelled by user") -// return -// } catch { -// let error = NSError(domain: "AuthError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to retrieve user information"]) -// completion(.failure(error)) -// return -// } -// } -// } -// } +import VKID + +protocol VKIDAuthServiceDescription { + var vkid: VKID? { get } + func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) +} + +final class VKIDAuthService: VKIDAuthServiceDescription { + static let shared = VKIDAuthService() + + var vkid: VKID? + + private init() { + guard + let clientId = InfoPlist.vkClientId, !clientId.isEmpty, + let clientSecret = InfoPlist.vkClientSecret, !clientSecret.isEmpty + else { + preconditionFailure("Info.plist does not contain correct values for CLIENT_ID and CLIENT_SECRET keys") + } + + do { + let vkid = try VKID( + config: Configuration( + appCredentials: AppCredentials( + clientId: clientId, + clientSecret: clientSecret + ) + ) + ) + self.vkid = vkid + } catch { + preconditionFailure("Failed to initialize VKID: \(error)") + } + } + + func authWithVKID(with presentingController: UIViewController, completion: @escaping (Result) -> Void) { + vkid?.authorize( + using: .uiViewController(presentingController) + ) { result in + do { + let session = try result.get() + let passwordGenerator = PasswordGenerator(length: 20) + + ProfileAcknowledgementModel.shared.firstname = session.user.firstName + ProfileAcknowledgementModel.shared.lastname = session.user.lastName + ProfileAcknowledgementModel.shared.email = session.user.email + ProfileAcknowledgementModel.shared.password = passwordGenerator.generatePassword() + // session.user.avatarURL + + completion(.success(())) + } catch AuthError.cancelled { + print("Auth cancelled by user") + return + } catch { + let error = NSError(domain: "AuthError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to retrieve user information"]) + completion(.failure(error)) + return + } + } + } +} diff --git a/Everyday/Support/AppDelegate.swift b/Everyday/Support/AppDelegate.swift index 573a2e0..b1e5298 100644 --- a/Everyday/Support/AppDelegate.swift +++ b/Everyday/Support/AppDelegate.swift @@ -33,9 +33,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } -// if VKIDAuthService.shared.vkid?.open(url: url) == true { -// return true -// } + if VKIDAuthService.shared.vkid?.open(url: url) == true { + return true + } return false } } diff --git a/Everyday/Support/SceneDelegate.swift b/Everyday/Support/SceneDelegate.swift index 6b5ca53..36158d7 100644 --- a/Everyday/Support/SceneDelegate.swift +++ b/Everyday/Support/SceneDelegate.swift @@ -6,24 +6,68 @@ // import UIKit -// import VKID +import VKID +import FirebaseAuth class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? + private var splashPresenter: SplashPresenterDescription? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let scene = (scene as? UIWindowScene) else { return } - - let viewController = NotepadContainer.assemble(with: .init()).viewController - let navigationController = UINavigationController(rootViewController: viewController) - - let window = UIWindow(windowScene: scene) + + splashPresenter = SplashPresenter(scene: scene) + setupWindow(with: scene) + + if Auth.auth().currentUser == nil { + let viewController = WelcomeScreenContainer.assemble(with: .init()).viewController + window?.rootViewController = viewController + } else { + let viewController = TabBarController() + window?.rootViewController = viewController + } + + splashPresenter?.present() + + let delay: TimeInterval = 1.5 + DispatchQueue.main.asyncAfter(deadline: .now() + delay) { + self.splashPresenter?.dismiss { [weak self] in + self?.splashPresenter = nil + } + } + + checkAuthentication() + } + + private func setupWindow(with scene: UIScene) { + guard let windowScene = (scene as? UIWindowScene) else { + return + } + let window = UIWindow(windowScene: windowScene) + self.window = window - - window.rootViewController = navigationController - window.makeKeyAndVisible() + self.window?.makeKeyAndVisible() + } + + public func checkAuthentication() { + if Auth.auth().currentUser == nil { + self.goToController(with: WelcomeScreenContainer.assemble(with: .init()).viewController) + } else { + self.goToController(with: TabBarController()) + } + } + + private func goToController(with viewController: UIViewController) { + DispatchQueue.main.async { [weak self] in + let nav = UINavigationController(rootViewController: viewController) + if viewController is TabBarController { + nav.setNavigationBarHidden(true, animated: false) + } + nav.modalPresentationStyle = .fullScreen + self?.window?.rootViewController = nav + } } } From 8dc2e3bd3f52eedc9d692e5bcb11ad5443fc198a Mon Sep 17 00:00:00 2001 From: MX126 Date: Tue, 5 Mar 2024 01:02:27 +0300 Subject: [PATCH 09/13] refactored transition in router --- Everyday.xcodeproj/project.pbxproj | 139 +++++++++++++----- .../xcshareddata/swiftpm/Package.resolved | 74 ++++++---- .../UserInterfaceState.xcuserstate | Bin 161313 -> 190485 bytes .../xcschemes/xcschememanagement.plist | 27 +++- .../ProfileAcknowledgementView.swift | 2 +- .../Notepad/NotepadScene/NotepadRouter.swift | 17 +-- .../TrainingScene/TrainingRouter.swift | 30 ++-- Everyday/Support/GoogleService-Info.plist | 14 +- Everyday/Support/SceneDelegate.swift | 13 +- 9 files changed, 203 insertions(+), 113 deletions(-) diff --git a/Everyday.xcodeproj/project.pbxproj b/Everyday.xcodeproj/project.pbxproj index 475e02c..989e278 100644 --- a/Everyday.xcodeproj/project.pbxproj +++ b/Everyday.xcodeproj/project.pbxproj @@ -73,6 +73,15 @@ 9E5B754D2B7F9D7600E2BDE6 /* ProfileSetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E5B75372B7F9D7600E2BDE6 /* ProfileSetupView.swift */; }; 9E7C19972B8BF1340006D48C /* PasswordGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7C19962B8BF1340006D48C /* PasswordGenerator.swift */; }; 9E7C19992B8CC3E80006D48C /* NameGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7C19982B8CC3E80006D48C /* NameGenerator.swift */; }; + 9E7EC40F2B9670E8001333C1 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC40E2B9670E8001333C1 /* FirebaseAnalytics */; }; + 9E7EC4112B9670E8001333C1 /* FirebaseAnalyticsOnDeviceConversion in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC4102B9670E8001333C1 /* FirebaseAnalyticsOnDeviceConversion */; }; + 9E7EC4132B9670E8001333C1 /* FirebaseAnalyticsSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC4122B9670E8001333C1 /* FirebaseAnalyticsSwift */; }; + 9E7EC4152B9670E8001333C1 /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC4142B9670E8001333C1 /* FirebaseAnalyticsWithoutAdIdSupport */; }; + 9E7EC4172B9670E8001333C1 /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC4162B9670E8001333C1 /* FirebaseAppCheck */; }; + 9E7EC4192B96711A001333C1 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC4182B96711A001333C1 /* FirebaseAuth */; }; + 9E7EC41B2B96712C001333C1 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC41A2B96712C001333C1 /* FirebaseFirestore */; }; + 9E7EC41E2B96730D001333C1 /* VKID in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC41D2B96730D001333C1 /* VKID */; }; + 9E7EC4202B96730D001333C1 /* VKIDCore in Frameworks */ = {isa = PBXBuildFile; productRef = 9E7EC41F2B96730D001333C1 /* VKIDCore */; }; 9EE8AE052B7FA45F001D126F /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 9EE8AE042B7FA45F001D126F /* Localizable.xcstrings */; }; 9EE8AE072B7FB77D001D126F /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE8AE062B7FB77D001D126F /* TabBarController.swift */; }; 9EE8AE0F2B7FB8CF001D126F /* SettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE8AE092B7FB8CF001D126F /* SettingsPresenter.swift */; }; @@ -102,9 +111,6 @@ CE5E73672B9124C2007620A7 /* GoogleSignIn in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73662B9124C2007620A7 /* GoogleSignIn */; }; CE5E73692B9124C2007620A7 /* GoogleSignInSwift in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73682B9124C2007620A7 /* GoogleSignInSwift */; }; CE5E736C2B912559007620A7 /* PinLayout in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E736B2B912559007620A7 /* PinLayout */; }; - CE5E736F2B9129C9007620A7 /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E736E2B9129C9007620A7 /* FirebaseAppCheck */; }; - CE5E73712B9129C9007620A7 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73702B9129C9007620A7 /* FirebaseAuth */; }; - CE5E73732B9129C9007620A7 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73722B9129C9007620A7 /* FirebaseFirestore */; }; CE5E73762B912DA1007620A7 /* M13Checkbox in Frameworks */ = {isa = PBXBuildFile; productRef = CE5E73752B912DA1007620A7 /* M13Checkbox */; }; CE8BF53E2B93302400A0A963 /* NotepadHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8BF53D2B93302400A0A963 /* NotepadHeaderViewModel.swift */; }; CE8BF5402B93603400A0A963 /* NotepadTableViewCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8BF53F2B93603400A0A963 /* NotepadTableViewCellViewModel.swift */; }; @@ -311,12 +317,18 @@ buildActionMask = 2147483647; files = ( CE5E73762B912DA1007620A7 /* M13Checkbox in Frameworks */, - CE5E736F2B9129C9007620A7 /* FirebaseAppCheck in Frameworks */, - CE5E73712B9129C9007620A7 /* FirebaseAuth in Frameworks */, + 9E7EC4192B96711A001333C1 /* FirebaseAuth in Frameworks */, + 9E7EC4112B9670E8001333C1 /* FirebaseAnalyticsOnDeviceConversion in Frameworks */, CE5E736C2B912559007620A7 /* PinLayout in Frameworks */, + 9E7EC4202B96730D001333C1 /* VKIDCore in Frameworks */, CE5E73692B9124C2007620A7 /* GoogleSignInSwift in Frameworks */, + 9E7EC4132B9670E8001333C1 /* FirebaseAnalyticsSwift in Frameworks */, + 9E7EC40F2B9670E8001333C1 /* FirebaseAnalytics in Frameworks */, CE5E73672B9124C2007620A7 /* GoogleSignIn in Frameworks */, - CE5E73732B9129C9007620A7 /* FirebaseFirestore in Frameworks */, + 9E7EC4172B9670E8001333C1 /* FirebaseAppCheck in Frameworks */, + 9E7EC41B2B96712C001333C1 /* FirebaseFirestore in Frameworks */, + 9E7EC41E2B96730D001333C1 /* VKID in Frameworks */, + 9E7EC4152B9670E8001333C1 /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -377,6 +389,7 @@ children = ( 9E53FB322B7F87BA00C55A45 /* Everyday */, 9E53FB312B7F87BA00C55A45 /* Products */, + 9E7EC40A2B96708F001333C1 /* Frameworks */, ); sourceTree = ""; }; @@ -646,6 +659,13 @@ path = ProfileSetup; sourceTree = ""; }; + 9E7EC40A2B96708F001333C1 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; 9EE8AE082B7FB8BC001D126F /* Settings */ = { isa = PBXGroup; children = ( @@ -884,10 +904,16 @@ CE5E73662B9124C2007620A7 /* GoogleSignIn */, CE5E73682B9124C2007620A7 /* GoogleSignInSwift */, CE5E736B2B912559007620A7 /* PinLayout */, - CE5E736E2B9129C9007620A7 /* FirebaseAppCheck */, - CE5E73702B9129C9007620A7 /* FirebaseAuth */, - CE5E73722B9129C9007620A7 /* FirebaseFirestore */, CE5E73752B912DA1007620A7 /* M13Checkbox */, + 9E7EC40E2B9670E8001333C1 /* FirebaseAnalytics */, + 9E7EC4102B9670E8001333C1 /* FirebaseAnalyticsOnDeviceConversion */, + 9E7EC4122B9670E8001333C1 /* FirebaseAnalyticsSwift */, + 9E7EC4142B9670E8001333C1 /* FirebaseAnalyticsWithoutAdIdSupport */, + 9E7EC4162B9670E8001333C1 /* FirebaseAppCheck */, + 9E7EC4182B96711A001333C1 /* FirebaseAuth */, + 9E7EC41A2B96712C001333C1 /* FirebaseFirestore */, + 9E7EC41D2B96730D001333C1 /* VKID */, + 9E7EC41F2B96730D001333C1 /* VKIDCore */, ); productName = Everyday; productReference = 9E53FB302B7F87BA00C55A45 /* Everyday.app */; @@ -920,8 +946,9 @@ packageReferences = ( CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */, CE5E736A2B912559007620A7 /* XCRemoteSwiftPackageReference "PinLayout" */, - CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, CE5E73742B912DA1007620A7 /* XCRemoteSwiftPackageReference "M13Checkbox" */, + 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + 9E7EC41C2B96730D001333C1 /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */, ); productRefGroup = 9E53FB312B7F87BA00C55A45 /* Products */; projectDirPath = ""; @@ -1265,7 +1292,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = LW5X22QCW4; + DEVELOPMENT_TEAM = 72F47Y7J7T; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Everyday/Info.plist; @@ -1280,7 +1307,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = ru.tech.Everyday; + PRODUCT_BUNDLE_IDENTIFIER = ru.Everyday; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -1295,7 +1322,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = LW5X22QCW4; + DEVELOPMENT_TEAM = 72F47Y7J7T; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Everyday/Info.plist; @@ -1310,7 +1337,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = ru.tech.Everyday; + PRODUCT_BUNDLE_IDENTIFIER = ru.Everyday; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -1342,6 +1369,22 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 10.22.0; + }; + }; + 9E7EC41C2B96730D001333C1 /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/VKCOM/vkid-ios-sdk.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.3.0; + }; + }; CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/google/GoogleSignIn-iOS"; @@ -1358,14 +1401,6 @@ minimumVersion = 1.0.0; }; }; - CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 9.0.0; - }; - }; CE5E73742B912DA1007620A7 /* XCRemoteSwiftPackageReference "M13Checkbox" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/Marxon13/M13Checkbox"; @@ -1377,36 +1412,66 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - CE5E73662B9124C2007620A7 /* GoogleSignIn */ = { + 9E7EC40E2B9670E8001333C1 /* FirebaseAnalytics */ = { isa = XCSwiftPackageProductDependency; - package = CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; - productName = GoogleSignIn; + package = 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAnalytics; }; - CE5E73682B9124C2007620A7 /* GoogleSignInSwift */ = { + 9E7EC4102B9670E8001333C1 /* FirebaseAnalyticsOnDeviceConversion */ = { isa = XCSwiftPackageProductDependency; - package = CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; - productName = GoogleSignInSwift; + package = 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAnalyticsOnDeviceConversion; }; - CE5E736B2B912559007620A7 /* PinLayout */ = { + 9E7EC4122B9670E8001333C1 /* FirebaseAnalyticsSwift */ = { isa = XCSwiftPackageProductDependency; - package = CE5E736A2B912559007620A7 /* XCRemoteSwiftPackageReference "PinLayout" */; - productName = PinLayout; + package = 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAnalyticsSwift; + }; + 9E7EC4142B9670E8001333C1 /* FirebaseAnalyticsWithoutAdIdSupport */ = { + isa = XCSwiftPackageProductDependency; + package = 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAnalyticsWithoutAdIdSupport; }; - CE5E736E2B9129C9007620A7 /* FirebaseAppCheck */ = { + 9E7EC4162B9670E8001333C1 /* FirebaseAppCheck */ = { isa = XCSwiftPackageProductDependency; - package = CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + package = 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseAppCheck; }; - CE5E73702B9129C9007620A7 /* FirebaseAuth */ = { + 9E7EC4182B96711A001333C1 /* FirebaseAuth */ = { isa = XCSwiftPackageProductDependency; - package = CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + package = 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseAuth; }; - CE5E73722B9129C9007620A7 /* FirebaseFirestore */ = { + 9E7EC41A2B96712C001333C1 /* FirebaseFirestore */ = { isa = XCSwiftPackageProductDependency; - package = CE5E736D2B9129C9007620A7 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + package = 9E7EC40D2B9670E8001333C1 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseFirestore; }; + 9E7EC41D2B96730D001333C1 /* VKID */ = { + isa = XCSwiftPackageProductDependency; + package = 9E7EC41C2B96730D001333C1 /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */; + productName = VKID; + }; + 9E7EC41F2B96730D001333C1 /* VKIDCore */ = { + isa = XCSwiftPackageProductDependency; + package = 9E7EC41C2B96730D001333C1 /* XCRemoteSwiftPackageReference "vkid-ios-sdk" */; + productName = VKIDCore; + }; + CE5E73662B9124C2007620A7 /* GoogleSignIn */ = { + isa = XCSwiftPackageProductDependency; + package = CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; + productName = GoogleSignIn; + }; + CE5E73682B9124C2007620A7 /* GoogleSignInSwift */ = { + isa = XCSwiftPackageProductDependency; + package = CE5E73652B9124C2007620A7 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; + productName = GoogleSignInSwift; + }; + CE5E736B2B912559007620A7 /* PinLayout */ = { + isa = XCSwiftPackageProductDependency; + package = CE5E736A2B912559007620A7 /* XCRemoteSwiftPackageReference "PinLayout" */; + productName = PinLayout; + }; CE5E73752B912DA1007620A7 /* M13Checkbox */ = { isa = XCSwiftPackageProductDependency; package = CE5E73742B912DA1007620A7 /* XCRemoteSwiftPackageReference "M13Checkbox" */; diff --git a/Everyday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Everyday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ea3ebad..226d000 100644 --- a/Everyday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Everyday.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,30 +1,30 @@ { "pins" : [ { - "identity" : "abseil-cpp-swiftpm", + "identity" : "abseil-cpp-binary", "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/abseil-cpp-SwiftPM.git", + "location" : "https://github.com/google/abseil-cpp-binary.git", "state" : { - "revision" : "583de9bd60f66b40e78d08599cc92036c2e7e4e1", - "version" : "0.20220203.2" + "revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c", + "version" : "1.2022062300.0" } }, { - "identity" : "appauth-ios", + "identity" : "app-check", "kind" : "remoteSourceControl", - "location" : "https://github.com/openid/AppAuth-iOS.git", + "location" : "https://github.com/google/app-check.git", "state" : { - "revision" : "71cde449f13d453227e687458144bde372d30fc7", - "version" : "1.6.2" + "revision" : "3e464dad87dad2d29bb29a97836789bf0f8f67d2", + "version" : "10.18.1" } }, { - "identity" : "boringssl-swiftpm", + "identity" : "appauth-ios", "kind" : "remoteSourceControl", - "location" : "https://github.com/firebase/boringssl-SwiftPM.git", + "location" : "https://github.com/openid/AppAuth-iOS.git", "state" : { - "revision" : "dd3eda2b05a3f459fc3073695ad1b28659066eab", - "version" : "0.9.1" + "revision" : "71cde449f13d453227e687458144bde372d30fc7", + "version" : "1.6.2" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/firebase/firebase-ios-sdk", "state" : { - "revision" : "7e80c25b51c2ffa238879b07fbfc5baa54bb3050", - "version" : "9.6.0" + "revision" : "fe09d61a539e11fdbe24f269bba10144b6145fe2", + "version" : "10.22.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleAppMeasurement.git", "state" : { - "revision" : "c1cfde8067668027b23a42c29d11c246152fe046", - "version" : "9.6.0" + "revision" : "bf3bb24f6b60a7acedaef504e9ce97154203217a", + "version" : "10.22.0" } }, { @@ -50,8 +50,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleDataTransport.git", "state" : { - "revision" : "a732a4b47f59e4f725a2ea10f0c77e93a7131117", - "version" : "9.3.0" + "revision" : "a637d318ae7ae246b02d7305121275bc75ed5565", + "version" : "9.4.0" } }, { @@ -68,17 +68,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleUtilities.git", "state" : { - "revision" : "bc27fad73504f3d4af235de451f02ee22586ebd3", - "version" : "7.12.1" + "revision" : "830ffa9276e10267881f2697283c2fcd867603fd", + "version" : "7.13.0" } }, { - "identity" : "grpc-ios", + "identity" : "grpc-binary", "kind" : "remoteSourceControl", - "location" : "https://github.com/grpc/grpc-ios.git", + "location" : "https://github.com/google/grpc-binary.git", "state" : { - "revision" : "8440b914756e0d26d4f4d054a1c1581daedfc5b6", - "version" : "1.44.3-grpc" + "revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98", + "version" : "1.49.1" } }, { @@ -99,13 +99,22 @@ "version" : "2.0.0" } }, + { + "identity" : "interop-ios-for-google-sdks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/interop-ios-for-google-sdks.git", + "state" : { + "revision" : "2d12673670417654f08f5f90fdd62926dc3a2648", + "version" : "100.0.0" + } + }, { "identity" : "leveldb", "kind" : "remoteSourceControl", "location" : "https://github.com/firebase/leveldb.git", "state" : { - "revision" : "9d108e9112aa1d65ce508facf804674546116d9c", - "version" : "1.22.3" + "revision" : "43aaef65e0c665daadf848761d560e446d350d3d", + "version" : "1.22.4" } }, { @@ -140,8 +149,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/promises.git", "state" : { - "revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e", - "version" : "2.3.1" + "revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac", + "version" : "2.4.0" } }, { @@ -152,6 +161,15 @@ "revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8", "version" : "1.25.2" } + }, + { + "identity" : "vkid-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/VKCOM/vkid-ios-sdk.git", + "state" : { + "revision" : "005d6876b367840e8ab5741fd6f69bef2d48f0d7", + "version" : "1.3.0" + } } ], "version" : 2 diff --git a/Everyday.xcodeproj/project.xcworkspace/xcuserdata/mk126.xcuserdatad/UserInterfaceState.xcuserstate b/Everyday.xcodeproj/project.xcworkspace/xcuserdata/mk126.xcuserdatad/UserInterfaceState.xcuserstate index 9f69d1e4299316589a53195b2aea6f035a074827..54a27213b440aeb21a0b06046106ca3249516c5a 100644 GIT binary patch literal 190485 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 z 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 literal 161313 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�JL2M3`+Qb21Q-mLV$%fBiD zyqfa#2mPpSSLg(Bpu^gl=Q!Y7Z@`+t>2JZbT4^LLD4uAqk+a9ysqA`Up&O?&y{%KI zl5tK-R9P*9RGhXY>Sl#9S?3OAT6j9z+4*c!D3fz;QKre;(GDYfP@zm-@a#LJvKg!W z`^b_<6*|B{r@x=Ay!I6HqRd0u+vV+4DAMCBrU<;PH&k6(o)-K4cNBR>p~!jXlstx$ z(iJY-58g&qyRfy&_<}-}UO};Mdn>24D)e{c-m6sHCn)~eUd8{->QCHg*JQo>JDM~q zG${;<8``4D|NZ_#eknlgm0GQ#^0w0Ze*eFXxRJN&t-Jl6((M6fVW>Trv7*PFDlcbA zQ+~B46+TjEQ4E??c3TLH?|lB7SEX`*a_qg_%}%^Hjc+&Zzl?<=o#OeGSM+IInx84O z9DH^Mnf&cG_X~v#Ljh79|Akcab>^o*nvA8^?CBeYe#3*}*Jm5~nyc_2SlS6@{ZSzT zoLzg?9k$<$2#Uv3Il;GWF#M*_p#&CFr?U+WabfjO`E%Qh`7})VghIeE=cbZ>8lxLW zD^wYG7OFrkoi!uil(YHansQia&EFQ%ECPe$6Exe(x1@V0WSSck z8``4M|GlYpba+mvs`bGLTyLf0VVGZATRlIkO?+^cMh)0R%jEEwCc|E7dzlGbKZRZw zoQ->YmmfCjexh-6c()p#ZPKma9|KF^9wzM=W0rxVvW7&W5 zpRq?;^RM{|T`oHt?L_i>HsIw}(RZ$^X!f)Q{JuEPFgGXh(d?E0VwB) z1F?l|vSmEO->s@A6=Kz&g@>;;3q?E$n$}wFZiNDC050d=88xwJ!`A+088;oJejkI8My%e682fb zTlHgpO=^fm|Ca#M8V=E|ki%(tVhGq@6K8DH1G5G{0pTy)&Ozy(uQ<#L8$Lz-BGn@HD1&6#- z!66UttjFZDaU4Du$Kgx=;xIbRsS#LO|5G^R(*TEjIwtqTaL8u?4uKs+{{sV1{;!D7 za(BKbfROKj$>;0&^Dz0snSqe+!xu$C$QQ~Wd=c0(lW%S2 zgE9P-@#TDo=)ljE@%MHde+Mx60VY3`IpIhDBJe+ez&aU$@V2LS;s{&_2;{z&IUxbB zJ-T0Eg}veZeu~87CH@i_gBX(s>-nXaeD@47xQt%`km8riuef?o+SI^b$-_IO-pAyj zRwy(u+9+4%SE6~Vr4_#3>Csmu6QUvBiJSRb6@0Fe@%eEBe-(cv)CBdlsw`gQZho_j z(A9iB-@vco*YfN5_522YBM&R$6HI=J$29w_^pCGM0 zA|IdbSNVN1Oo8isU(W;A`QZ#<`X>L5!YbdES>=zw`S^pfy#A>bunc4`pMpz*h`0J7 ze^|lg$1*N|ZKrg+#4-K{8J3^(U+`b@U-4h_$N6vgZ~5=|?=ks1CjY?XpP2j$lP54m zUikI%iln(eNrT-U}|MRdE)BsCCgDEx! zOF<8?6hy%w|6odmDNgwWSoRbxvFR3Uf*oKfBw|Xa7aW*UpBXF#m*9=UQt$vQDGe|@ z0hrJsOle!=lAk5|;_Y=7xWE%8V%srmUECtrd+@-0g*k#^WxJzT_~3kS%xW3y%55b z_Y4tPAyg`eoFgOB2dqx00!B&sTLV%E`g$kDM0oryyh5F@Ktbkw8JQj1DIf3Y65$FN zm=_C@fQ3thrNX7cWy0mcGGRHUI%BE}rn+LP8>Uh*m4>NwOl4py6H{56g%vSiUZd=B zgzIHsX2*e<8{6YhJ^qE|e*l)NWmwi@Dkl!hwNU|1fDo58%x`236F!{4*JQ^sM>_DaQz>=9(6 zkMNxEyzqkXqVSUNvha$qS9n!;4O8c1su!kuW2z6P`eLdOQ$?8ShpGOU8n9W28GVG9 z(MOPtKGeWC5C_MBIO1O*{s(|48-0YMm@19~Q8xMrUy{esVWATCEs;)Uwfs z8Ywfxzhs6wyj7Wa39VW-`lxkky;@Wo)Cp>%+N3tCEozX zQxh>Y2~(3dt7AqVwNu&BsAZ!MH6@P2V0=qMmH!LG|9K#)Wvh=GP6~{ z;AaV@BABX;e%1j)6hyC>7oYG;)tAe7ybM$G>($FJwcrf#c%}N9sC-smE#q;a46W;A zJYLuukCfWiyR)J(##_Bvt(bh&vdM>9+)n9uiM!RZ#YeqbU9WCXuTig6uT!sAZ%}Vk zL+ck~O2QPz)Ft@;WADA=qp04v?M-%eW@olYC8CcnjHX$~98jPkFO)s;MFOmM-vLqi?ShcMv5?nkLZWef6X|be zBX4Opa{n7?mSLn>A^r6^Bh3~VX|~GGFr>eM`yjJhgvwOzYMYDA9$0C1lYV8|jBb)u z`B`ZWnj`Sa9OAa)YP22AQFN5+@i2KW9p%EOiNW9J?yPOvfjgSJWW_XhW--yzey%x+ z)YwN0ueBs)=7BKNTyE}Zt}yp9_cr%2_cix3_cx=_fiDDZ#n79Guic%b$1c~B{%+FW zL;7_Y^B~ns^H6i8d6=$)xth(qS2J@x=^rBf!))dw?Pj)tnd8_@H1zM&%$x)>_xS+P zJk5L*J6S{e4QX>N>F>|e$vX3Fc5)^=`2agv&-XJA?&W^QA=wf`%5zE$O zWF;R(tTfkiq+$)jUB)($@iUeY zy*i(0GHz34+zuJHXEpp(-9kpMcCB}qe`FPZApPfQ^G~GzB2N`}nt$UMxr<}ummDL1 z=NQT3EL!yW+?qR=uW`X(_U} zEO;XG4e7rn{dc7Qp7dyt;0%5wJsj?#IFA;w&N-Jl(Jq-C_~n%4}(w3E$RhHG38!b0kZnoS)f}ex{2|*G-!PzkPCDzJk*qW*YbfX;rlFMmwb|ZYWa>W{LJ#X zaVJ~Y zN3*b>77`C=cX0nZXcgh06*X1goP$;c4i;KXCo#>qhiOzdnuS(}wFnkkoh0;6TU{g! z$j?Hn*BZ!LX!Wy&0}3N^Ynip&+S6KLg=#}ds3c(+2~{LilQ5iw14%fDgb^ehoU!&%Ewm0W)tOGxb+8U* z3lGsO9EBTcE(^rMaqS+qfrp2(hoeXssd;!9JhYD0Wg+2EjGN#MD&~lGt*2OzU=t4~ zVRYI$m4q>Qns}6Tx@zLlY~o=EZq_=Ehr-wvDmskX*fQ%e*14*SbJ)f4t)tCg!Me!0*m|P%Bl)lh3o~&eZM_XQ(!#90+(cu57^1AB%Gi*`7xa2 zu5Z&4-D;jW!%qqS9#&@EX5G#@enrCKwDoHe@Yp$@8C=%yt>_Oz7o+tD4vr_WP(QO! zOIir!5L}v5yRF%2U)`<0vxTR$k|>wLrngyPp-r$EY@$uF8Evvnv6*aUn}vjC5{QIT zNmxe0X(Zsb>kJZb+jSNRXJ>3S)k0g5I+(}iVGGaEEW{)Wb$)`-{R^U^l7`OnYKLR%kOe^_Yi%R%u11V!5b z4vM&W-iw73HK&H!vLk@H+lH}){D|5%fYrUQMItT5!L|u(;UTt>wnJ^BY@=;sY=_y# z+Q!+&lW-{smyv*4;0hA1B;hI&R*-Nt3D=NtZN@e+XW`*F3#YM#+9PTqy~o0v+JoW# z4~DimY$0kY?FqGQ0W7o~r^`aZ4cu772Gz4wyVQ$pC$fo)Nm!Y-okT*O&!=rmZI}SI z($>r-^7CoiGB)wXy_s0JUOU*?wsW(!vTZq=cr%;0j7{9u?Ap&cJWzu@qTvk1&oytFyXo7SP7@D;H{e-1#7iKZn9!(@F)q7k$@9;f&`qvMiQPP z0S(A!NO(45`y!|0_FQoMj+J~)QxeC`Rnf1u8`%a%{=r86Ny76vBkct+65YF5xIcGD zcC)8n(QdRW(9tfF@M79-BH^X{bhO*-PL6V6yMvpGFC)s?T^!|JX`z%uSeX;i?z0E8 zq0t^-5npR1k(MHE?*vX|I9*gM)g**n|2*t?RjnS|F#c!Pv3B)mz&TO_0$aG-{+s=G`yci{?SDCRjsi!a1Hw7T;3Pv48C+y2CWD&{9x`~z z;3I=S<1nZeI%Ksg(P3c=1Db{5TvwtY(JtZsm(US_gpME?f;kBt5lHBW>avg_ga#sS zP%S%iSK86R(Fr0tI+7uhc625~G{11@=lW(Lj&gWuXL0n92(+#3x@>*w1f3^ zU>FeAgL3p|5t9(nQO@>auJ(TxkWf$H9(6$WTIt z4rD;iJCOl7??Q&IWavhQ?qn#)`DEysb{t2BiabSJ=-~PHj^kOx zUM%8b7P0r;`p2{lrV-**(ioN%#;@OT%S;cc4%N^%B&U2jaxWI9t z<08k!j!VcefD8l4Fo+BXkYO+x@HHDshDtIFBSTfjaam5qt4wtTJE7vWtYWpM;s_qe zeFvL3s@=pkF!5G4@isCH*G#;VgW_F|wG0^!B*Q`K7Gd!K`*=-|4UPxc$NR}}aN6-8 z84k(Q$44FL0$S;KjC~x*K0e7l9=bOlP1@oWj^`XNsy4pBHjZW+pJW>`PkSGMag*bH zwsEuLb;lcyEsi%GZ#mv}yyJM+@g5ltBg0rSj3dK%GE5-DL^4bw!(=i{A;aMr#|JqZ zKhD+ApRH5qrZjJq7W88RG6hH2^+G79!&PDW>e zQx6%PXz?GFb_!(3bLzCy=rplcVW+~)MV>nCw6IrunL1r?sCF=?vp6fG)5S9K)aiXC z(ozJRC6Lh>bcUQ^XT%wG#+-3y!kKiY$S{ixv&m3ThGWQZEE(pIVJ;cwkpY2zLB`oZ zmC@Oy;8$liT?c0=%cxDAHZ)=JC&OY6jVHE;#{C}}or7Sb6IGTrb=o-;HaaVHS;)}H z?L}<3i+h81tw%TyVHFQ1!@{(4BpHs+FD^RAIMMsVDvo6pPhhJiu!@*<{htu$So5l* zV2yUXBb?Jz8;@ig`LXrB(rGDXIOnsCb?0as%hS%w$Z&3+K3?U#M)mP(_VGOS z>N@rj53>L3qamyvY?bpSRmK}x#tU0Xq@}pcxt?Xb-Fb)ePUl_Dwa&Yp_c+%%?{(fs zhKtF7Y+p(SWczY5TtS8_$#4}JR*>Q9jB`Uy#)m9HC;E1rkFku`Xfj?$d;_zJWnA4Z zV;ji$GRyc18Lri2+yoi-IV08iw)0)q@EtN-pLU`Rc0-;Te(3xJMmay?=3*MnMdzp7 zTwJ-g=AyOOK1$PSyYpLB#BW%{8(G9p+1`~c?A22IQxP=V(8f3_TouILddiM@8+)0MJGDSL7#3G^KS6)S;$jBnD)kM6f`S$E0 z5{3=!8t#7$i`>w#2pw#9=QJ$xx29oHtSA8ui{fNhmoCC(x;H-!i#ir{flo!9Si}3E zVNqAsaQ)si)W>s56_pqD%1T&N!4lpN35&Y2gzNVuVbOr1;gGOsV9}tW1BwP04JjI0 zR9Q5vsH&)%47kU7hzt*t;Sn-CN`}YC@HiQsAj6Yn*qA9gFel+5>Rn6GXqNCPO~Plj zyOx*QC2Ru;k7Nm_k>P1g!dggZI;m(n!;9+}Fmau?sF-_ccGMRg%POMT|6IBV&Hm@} zRB=I3BU=?NYT$~Q*X%A@$X31B!YW6>2<>1e7M-lBxP(>YC)WE)q@`F^bUv$iTG8o6 zXB3@TbXL*XMduVPFFLpAJTkmWhS$iji42>`@H!dZAj1|iyh(<)$nbWi=z^Szm*iBu zf>nG+Q}KOG#gE%nYy%ZzK3?OCyJg@Rouube$q-JEyW8(TUf;x zi(V>vx#*RmSBqXN+Elc;==CCq_Zb;JC&L$H_>v6U$nX^zwv*v&GJHdZZ!<-2=2Uz) zr{Y#t@jFe$9h!>2w5!+#Dt^N%eoKb$H5GSoR9sScHN%6pU&(Ivba5B$EZWT)?jpkv z>7w7r@ME4D{^csnYUnCp4S#}BE`c@txuu5E?>VVlvdf&+&}Cu`e{Cg^mcr=@K|@!O z%jGI|xm_NY*X48hT>)2+49GLOr;z90$?yjm&}RILL>-9*Bo<~|VO2v{+?8-8bsbzK z&`{LpG!zXaDkPe4t0J1)Mcn@)x+)-|s~3qvPDEEpB#LQQC5cjgBD#jVM!+f8foLU)Mzj)L2cwlJ%6n@i3L6tc%5u~3Ma{6Wt_iA> zTAvLtmmDY=!Gu z)x>Mq#CR)-v=pmccd&`8T{pUJa^38@#kIzjaoy^=&2>A8Fe^o335gv@>_}oK5<8RF zg~YBTcFVZ#%$azPT1mUsvx(g`6MN(;X|bYR#5NESYc8f;Pm@@xiTE5u+}mQw+I4=_ zwTU%+jl{CFYcq-Ed20Bk>m60Yw^_rUFzSCSd+hqq#a%yz-Cg{W4Y5}qDYm)zB^$1< zT-#k=yS{OK>-x_1y=#Z-2iK1z_93w^iTz0IPvQU)2a-65!~;kiOyZD?EBBHO*REVN z{DU1FsyR4pPc%HJUBdk@VKKjCqu5MhWlq9ke#wU3;n>aKkpe&U%Wn5n(Z%j!FElJh zT~?JY_K{efpN7Su;wYpl4s#Vf99492jH~Da_f|z0o|JRGxI=O0tck^)*u)Vqu{g#d z^uQJ&R7=sLcmPZ+E-NlC?pa(>+^e{Eai8M8#r=w5-ytN9B=JxZN0B(1#4#iuM&ei! z$B{TbQ#??OhQ&iv6N{_Z#0i>-llGW6wcW%vFmWuKhzl`MGjU?pM6*@zFk9I{EdQC^ z{%zus#Wif=G!iGLi;p64N}eXpD4vxKh{c%uOyc1z6|a>j9??Q7N8u99t9ix8sU|L9 z6OU{qk(T0w;#1kgMa7GYPb@yEcuDce#itZ6Ep9F*5^G3AhHFVYn#AcO&L9!Z#+f9} zB5`)6cv;TGGu3*zcsZL`ubFtPRxi(Q7qJaQ#Kik_@d^@;(L}r!A{JgS8>2OBdfr;+%Bx%_PpvQ^H$|?@%SYoh6)y*-?de5@uDs(LzGar**~aRRiy1 z0~h3x;^E?F*}zANA1!{Y`0?T=ik~drSo~D+)5Xt_*g#?Pats-iHk`* zk;IcS#n0sod?{z(Yi!^W&A?MM1DCZM*aik}WdlDX@np@wPdF5Iz-%gj)tQE5*<;{W z#b2|5+euuSF8+qZ<~$ADQT!8pD*k~hWa0|>XReS>-AjdRpQ$xY?8xh|yFbUl%V3my5F2%Q3#072au&KP-PKtO z-BoPim93=FQXJx*$QF)tAL<_E9_=3EKFmGVJI!oT$OQ8%2{}X+A4I{u!VRx0skQpub);YmWsEwYuE-F&Seefk$9t~;c?kkq5PZP zA^()#?Sa-YZ|qAI&N?LLXbTk;ffsryt&<>p!U;u?fQH_y5kGkXb#j>2Zm ztFztbswVQRd+|0lk!Rf_*}mf8#crN;@4m!+srxebu45B% zE$-J$E9#_HlDdAHC)F z%W_(Id>(bmy@#jVi(6Vrrlp8`c*?ye;YoT@o)S+7Pe)HDPiIdT54x(~BJph!-y!i` z65k{7eG)$)aVv>vBY%|fgPZ2>Nc^6}9VGrh;*TW$MB>jR{zBrfB<{?37O4T!vqZgr z@ieoSyR-oLd+z>4YF`Y#4Z@@6e75oe5_fCi@nW{}66I@##NY5DN_7h>`)b#Eg$ES&x4+aJP&&wAxR*~K$1w3M3RvtnIwfI6G>*0EE&&Z zITbhNRD2dHO460&->`_TmLe9Ms%iCu=Vvu0{=_1p@wv}L zT8iJiB8&LD=MT@Hp1-_0Z-KYatM>|CDCi~0N0OhU07*fTLL`MrijWi~DVFg{s)$~b z^)#YFS4&;mRowq7dP7jri|didMMZB6DthC(EF>i{_<=Ww ziQ01yZznItU#GpDNh(QuyOPu)KNY<_yyy?Yjf}UPRqTk~YHu&X>R(c)mM)g8u^*dr z%R9h(K-Na@AhxkCi(Oc~u?mf_ZkavXlVDBN`k={eSqe$vbQYlG2NGc<# zoTQ#4Rglz+q~0X;$#}=)bR4h7Mek(Rv9G3Me=RN!ZkMqQWSq$|&LXLwCgU-X5u^07 z@UXlg+0CA)=snKc$SO9FG$8G5B57crDlYP#1f{%-(P)$gq0#7Ff<~isz}|XxByDz| z_f+rcs)whsheHq*y-PTh9?(KxO~d8h%UQ#7z2|w)_g>(=(0h^hV(%s1OTCwoR7uh> zlB!6mCTTcH2a z4c9_L=kh{3gSmapH)c0~Yq-Jt0Bd+ZNu$%=2T2-}r-qMudHy{j;^Q0<`Ss)8jcnA| z7DhSblQpTH^Q!ajy*&S38sADHEyX4;&%gI>_P*|Y!@I@%ruQxH+unD)?|R=OX(CCJ zNSaL26p{`n=?Idhl5`|V(@3hxct6N#__3!aPp9(o{Ci1T0basm>aVi%sifKM;jj(D zAy2^f{!Eg#0=$^bCQ9Ju`7u%=vVE}g8S3uH?v`6ZXjfuV@ma)FIR9X_hF9jQY0bkG;@`Zg7U(^@# z#eE4M)H;@=IV8;`X&y=QNm@YCaU>zSH|Qa8{9DR=%%9T8diV95(T2-*n#$ zU!8BJZn6sXX0_{BS7CmHc@+7 zxwKq+1SnnD9vAn2T=Xqt6LCefmzDd@WE01EMle_@i#r#y+rLdb-*+LKcmYZ0rhONY zbY7k&Ugpcb2QBQof=xW1r~iWjw(N=tH!?;dt>jW6T7 z)pwikcHbSoJAHTg*81)y=@ODIB?)cD%SpO|q$^3filh}JT}{$88Q;2`iyPDxn|u$k zi`QyV@p^5=CTUf>i*4ZI^X%daBweRPMa;!ttxVNrA$Z|**u<6G>}&n*!}po*OVz?J*uvF$r1;jiizWQd_q}h2?+4$HzMp(Q z`+o8L>f1@uO(fk+(k&$6=oyj_jc+6Ac9PIezBA+7os;lS{R;inx(@zAmhdi3!n>&; zNd+nH#ksHD!u@Zd-wq4?4wBa9EcClzVWFka3hd3R&`4i}kpSBGFn_=wf`fi^#@&beh&KM{#4dMf07-%7jdmHj%e6?TZ>?r3v2!^{_a@^{oUBX^?9VI@DGNA{$Bpx z{yzS`{(k=c{sI1h{z3i&NWu-)10>-F>miaJCg~B99wq59k{&1NiHv`U>Y%?$t(5%- zv4c-)4nDP~QhvT&!8TA3gR|3q+)8fL6g(UXdUvBE5#UaRI})+^Tf$oZbe8aFlAccc zXOQ$vo)XUXW3E1KRQ$)VgwGx%g z;S&GJ{!{!*{mp*zpXy)cKh2MJ;7cUEOwubPy-Lz+ByA#TGfA(L^ae>=GX67j9xgZS zbnHSbynsD?Q}Yn-EytAbBRLj+&@N&dh={@2Y5#R3y`_nmhKP9i_)2qHkEzahd;H71 zMRl|%9^T^5u!_*>owOe+y_=_sclz&!RsOrU8}U7KBl_>*Zp8QZ){Uq?SQG1h|3j*Z z53-6|S;c$U-}hVitEG6t{}QYCq<^FTDgV>{XZ+9lpYuQOf5HDENgt8)F-f10^eIW7 zk@Pu9Uy$@AN!v*JD&v1Sr{X5H8_~aoRm8{#{zK9?S~ubk?IN~;h@Y~ExF%m~B7O-G z_c>_W|DAsaOZYuW-=_UPkn~-i68_@frN%?7^iI;Xr>87LwNeN?}Y^eahdC+;F?H%Y&d^gBs^ zko0FJP^?NA@Tn38LM-85ISGvgISGx1b_w^tgn=%QFwm8Zx}1c8Qb@SZL5hLifxeJ1 z(1(nL=|Dd+>hqH@Feor2D`8+TBs2=}sgQ@@eBQ!AO{d`jo}ORWJ#Y{NG>ZQ_!RWx@ z?BAHcVS%xMae?uH34w`$NrB0MDP%N~Q6{58MiUv$WVDdcN=6$Q?PPRh0!QTht5Ms9 zf$8wi=+yjkY3)Lzw_U(C5D>$&(}4yu7HI-5Y*oM|fm2w(lgU_|4lE_3J5K?Z1vfz^8pp8qf?pH*kS!;Q4HzFOL+L1#VykFArQ1xH526U`62Sz%_wu1J?zvCu4w& zK{AHO7$#$cj8QVi$QUPMf{e*bAe~e2#+-s{SV7zm^B*#H*rQ~Vi0FMYfiH6&ex0j|zh@8oX&w&Ls^X#T z8n%Ikf3k*uk+FYH!(bsa4C)K7X2>`IYcTN!5A)19H-bvg3=xB<)&`}6sMavlARiHf zj$rn&TsT<7(U4zRA9S-*Ls~fHC>X6BED#K5MGS^m#L89@X(^JyQivE#1xtb*f*pgM zf}Mk1f?b2%g5AkjMaF6}4kzP*WITwBBgl9#84n@jNHQLp3HDG$3|6S`xexYb5l3kv z9)?b9evpLNII&&D{jXwhI8+Sc!i?5bJQymvP7RJ^u-Xk7$EaJ#c!YMf#|FoSM9LU0<(IH9GC(jx6((}U`;>>v-zHco0Kk(OdkkcVXl z=LY8m=LZ)Aj|(;g8-q>3g~8*=h&JNkWITe5Q^|NF8K;r4hKxs%v6hTSXM&4zGUkS5 z2YFbwak?gBofZ|3X;-lgRODgV!3)SZLsOB5Ww+9A7`!TYHEXznj5E{0YsiT433@L@8}CF49Y&L`snG9E`pw2B+a*hI#KWIR3-d^D%wla`?8 z5?zPjGpykWnud!Bi)f3#aZEg=UBosJ@eLMn3mF$_BEAg~_j#ur{4n@2YxofvPfQ0t zAtS~n1x3l)S4L;8?FMk3>>WL!qZ)5v%_8P6c&nPfbRjAxVaoJ>emH4G_g z8!=>M4VP;gUZ6$8OWP&f{}P6RkT8V1$a8ZNhN6%#6br=}GM-1q^VKaX=8pEUIX^<3 zLOdip)R~MIrbFoMxhOvwLp?$~Bs)~bGGa-(m7xlj@shpDC}{`l9~zXEF*J~6O5PR4OL87HxfX-&penv6HM%h(1o*0GE;$+%LJvA(s47+Mf&UM-o(#{w-KHy@3ZqT)Eru-8ptn1Gv1O%inBxfLbT91q2-}- zL+6Fg4_y$tFmzGq;?N~z%#acG-bTjT$#@4D?<6C3x|WQ0lkuKR=(3!FSLF=k7or*0 zX$Ib>8TdfEfo)(QzYi^hD|4@AAioc7pN~*N_k}jFf$Pb*J{`KBj2rSa@Zr#790niZ zFvzd8w}ub~1uQzU&xrPPC_5>?d+1p<@Ik~tYX~tAY4%Yehh7Q2!v?+@dM&gmv^n&8 z=#9{p(3_#RLT{51O~XgX_$V14Bje*_e1eSVdfG@vbUi(t3B8*$aI4;KMn_`k6E^S} z&A{h*TD=~#?8*2_yMt}u;0|{12QogZIruXiR2-pS8Pem~!*l8uRq|x5j{GC^7n}Ge z8DB_;b!2=oKNG`3Sjxu2u*k9SC3qEhOV(F^s;r57S}v#eI~gj3dLNA!GPZ4vQZnEQZH$>+qAkghhwx-oy}f zX1z{xY*Lsf<`;GkPhl%RXDi3B%Ad4QSxa$L_*k~GHhgq=dU!^-E<7_lD?B?~A3lbR zUy^Yf8NVXqb~1iV#&5{@Eg8Qfxc7E(D(?S43wXrt1*Vvy0k`?&T24F@6RL8RPAh_WrN5BM!(I!R66jbss5)jQi|a zj07Wi4wsJLvV_x-2+5KBM2sXNCE3^*NwJ7gL^u0Xz9;#tg@=hD?tcZwNViCjtc{UU zwlUF4(wvNu-jSh@G14c}H_|WCKQbUPFfu4|KxA-a2+1juOGxfOaz~Ook=&W&E+ls) zxf{vdGm%PF#>jB>hB|UE%UGJLtL3uX4Yk~>UBxy~aWbnoh2$Q&nmRI-RlFH8-W=3p z_T-S}N`45f-C9JZN9x$c86=mdBQr_vnWu}#MCL-M$gyZT$`xoj?tAG(O{m7m@v4Fg zS;5{=@PDkE7+DfIlNCHUa!O=rq&Y&7QzOeFr$tVWoI!G5lKYX|pX31~41r{KBjaGc16tYD?4V3jr;M;_7cU>i7i9XohE$-^`USGF1s*FO9WF2BClI^2k zC-P+EWwvl*$MxKj2A9*42V&o-~N0NLf$)iXfP4XC$4T^KPx6FJ zxD6Uw$0}c2mhjv8 z4(0X01T6RP-rv#i`^XQh;trChq$59)e0ZKJ{u)~GFNk2<2xXi*f+!lOv8 zCHZKQr<06$UPm(G`7DxWlU$#Px>XsY{%F84PS+tCW*LvsWSm3tahOueGB&i!xc_C0 zc7=>lw2zL>$r$Yc8P)Z`Y{%_c4h*Y3?2$3rC)y7(Mp4tvO-E7F&C5^5=mF88tW`KV zgqw-;5#pl5IK(YzVU@!eOAJZ=tECtn5gn;Yc?e6{*h*^6$+6KR*~xLy@zDvsHWJsTSu=7GjNIp=m*~gYAmYopgiuaDjk zO-ENoSCM=+$>)%~ocPe^k$gVM7m$1*$rq7)aVC0WPQx{7YcYB|Yj}yK;bnVTi&wRK z*ajYAtadv35XqNn9zF^WTN%6^eLDIqoA?aLm#3r8k$gp-CcYGXRgH_Ua9re92>g$6 z*wHP~w^a+@VhdN~kz#A~E0*xX=tt3yqn|`SjeZvWJo-iS%jh`0W7##!^h1F@O5P zxpniJM%K-n)igU7*J8m~Br9Po%o5(7M~YOe2PBM@#5%+}#yZ71$GXJ2#=6D2$4W`Q zlVt2=Ey;J2d=JU%NWPck`$%3-@`g;TOqDR!ORbP&{a8ZuV)Gx8AJi)3_SX%xL6>&y zKz8sTk{{3DUC4AI{UkDKT}tc8tes%a6dQ z7?0PMA8p~F{cg>|=`nS%lw*weWlS-%!%=E?bzJdyx9EMg4l7fhFD{)DYh_% z2H}$=ZzTCC!eY4St(TuA`8krGC;0`EU(CdE!?j~eFdo9H>k#AN+OqbV0r}PJc!(QV z$oAI^w1tN}U^{jJ$=YiMVmx3wc8OyxL-H$RfTX;|Bk11R)m{=U`y^vmTS@+q7JT-TYJsi1~oG;r5$^dWbIu8Fqh2a?ed^%KcIXX27- zV%(%(!LPQD+t|ckwCZ^$FT#|4wY~gDyNdf?#W*je9Y>t{HCI8$c`5CEKIV&ejN?VN z>3AoScctT9NZy^FhVjyPc~--C8EeRc7~(wqTK>JIhK8j%sp9?O1GBBf_yE@M&sGv? zDJtWKLc{p5cvZYQK0JP4{Gj-V_`&f*;v-4Xky1cPAt`!N1X2v7h@?oQ7)g;c@liPq z$EpD_J`ox!N=`!si;Al6M^o(W7Pf(fGuXm9QcRkKvs<-re*8GLZ~-Znbi9ESYn~P! zA789mxCj<1HV9>3#WyOuT3DzFwKRUJsvto@#gRvfv*MSqf@jCii7$_z8$U08e*A*? zh4G8x7n4#%ii?zDQrx6?Nb!>5BgIcjfRtb+erZm@D{~57!wQBp1tWVDOtdT51`1|a z!COfQYYN`cs)F~%@fO>3{612m>G%dxVtFd~Q2bFWX(s+oPQed6J>wsuGX9tq?4c>x6H8~4g7*rL(y!gYHgNEJc5nwNWtxLO!NK^? zMYl4fl;gRcy2V|}uUd%uJ^m+~_y;K!>G)ry^vch~ggzl=O-vZr#NN2yNEiwC8%m!R zDmr?W+ds@5FJVon1Gf`Aa9io$S~@L>C&44P6W)X`;ZFn-!9*w#PDB#XM2wVyqzoeE z08$2%GK7?&q*RhJjFc);sxyh)$n8W2weu#yBe#{|nvf%Moj1y;b{+S>jtL&Oo#;=> zfjJ!$JZ{^&J29Byb=(y!lFeJ_I7z$K)d?QAofuBa!Rf?7q#Tl`jw2I1Zo4p?7{xk{ zM3_q)hQO#C+R{do_I8WJ#Ke?rY)njM7e}{}NXuSL;uu!(s6=hz=*0BIj6_{xW@1)i zcA}n?!$=uR$~aQSlQMyniKI*-WilyKNI5){I982~iTODd8(GC8G!>83RIF`Ru?7ch=($mjLeI_roKuy!CUL!L z;B{=^(J=6T%&AJ;n7E4#yeV;W;+DjkL?&@-;K-^Az!&#QSPA#0s6HG;v_t%F%FP z%V?PT)vissPkfe8SIeOeYcB&dN{2WIV}hXD1UJ56{jg9wxga)wQ#eymq#- z{C~&8WJQwK&QA79_D=Rm_D%Ln_D>E-4onV89zY5L`1zzDfL}<;MWo;s`VvwuCFL?w zF3%)~s0Jphl&a)#U56yEovmD<8MuPLJ+i;W7QY>uD(_K0zw!S*ad}y3 zd5`j*HRUx2)z!{vnmxX5`s{H{wGB-Z7L-;WU)QjBM(yI#aSInLnBUM;I&%K>+Bx+n z)*d~luKS|tjZF>p^JX<_1$tKUTwT{y$+MH^B$tzN6DhdNx2#H@mpng-uPN#(6!Y5V zZZ&q_xVkxY)0^sMRB0msu-m5k`STj_yD<%QGwT`}>Shd^Kd*^L2h=wrjYV01~`+;@y>Kba1{hG#w4fF7WnqHf9OLfi3JCb+S*n5qrs@6)Ki)dJF zQ|+AjvvLnY@yp56k)8h*_t@*$NzVyi6K+ev6E^cuQNDqpn~(X ztG_<^fUfJx~Cwu@&Cxz1Ye2yGwK#J z%s=Lz7yoJXeDABV_i62X_k7p1zx-owI!jjT=aR4Ly55w0KKVlO#pFxLmy@rMg8oGm z_yeRoND7Mk;hU1LB{wBECtpv#kwl~N5mKHek<2 zWsN=guixZ;s{ZVsA1m4S$NrfGRphN4Ej}dW(dKhrPkvIcvEWHWj8BuFB_B_IF{LpZ zs_?}l<#AFTBV`>aPbG#v_0-pT_ghX){;!hXu>9MTUz73#DNn9UeyhXBH#QGw?lw`) ziIf*fd5M&lSEVc|YYNRR82cG1 zU+yOjbDmT#te-PuTwPNW*G8Ht|3?~TMMz;9V>;y~<<)=Ma@+= zD_cqbqXqEq51|6z^A+FA$yL=iE|^oh_)tVI9OxgXryXNr?VN>m|N2z!o3fXkseAcn zNosrHO8Fl3!7%+3vy!i8(ccBe%8DZ z^K$>2SYLMnH;DPf>l(T@o=`utX>cPq(?{0Ns~c3-qr4>hFMRt3RrD&Un>S<6&+&Ku zX|LWTjng@K_7{En<^DB#=FG;rra@&ryZ87ZE`F;FJ_b z9jr<%O*N;`-L`|2A4vIeRccx4wAAUO{6xyHq+rZKjXjKegRu+eW$&UEHI1#Cj=Pn{ zanonl&8=(9evSFgqQwVB);2bwH9iBs!2K#J)U1n@i`9hLbR~OB_wUd10kl(Eo;nY4 zM)!F0fOHBSHa|Ca+myNp5%l8JC6f?8o9gG*adYbZVLdKG>*^OZEMAtneB!8aRj4sm zrY_TI@1aaxnOd=DUssc|6Z^`=;_I`KuwxJW*SD-kS+^cN%Bst%`c;%w^y|leuc==! zd;Yw-`HeNT4Rd=}Xqii=ZqjvKom!b%m0F#;k(Aw}{6@;}r2Mfub#v;L)S6U=ls`%N zi%dE)6>x~`-@BsM@T!WcvTnVrs{3@S7+P7;t#5h1KHd6N4(;2oXV0O%dJV0}9j>u{ z?n2zL;?^#E)EfK18OJxxK+}18T{qld)sNvkjhRzBy>9mWIf!cAv|RQ_J*WNf@2uN9 z<$HdpAM-8?^>VCDU4qN-WYBos!Kl)IQGd8D`@^Se?ytUf)Se%%&;Ic7sC39FPwx5Q z1L`MdR32L~1V7Zu_u&+VG^A6HkV&6TJw_&>x#URb!!@j0wN2LUcC-{vrC!mw*QB0K zJ(GGi^<3)t)C;K>Q!k}nCX+}eiA+W^$z)Qn%LD}jH^0iqS{gLpIvCJuNu2k{p8Sw>9gybaF?~Pp>E2a#5MNfe;$Eb zB6Ege)8feZ@=kB4YpR>9c~N68hd0CKH`J+l?$)Ev(5kB5WtEVzcfW2Gefm~+>s#HU zPq#i5Rh7Ml53L+lQC&VEE8kRYA7y>I_c&ZtudHWRZ3DtwjNp87iV4Vj9` z+S{*k&7~T9j~1zh&7ZqqP93+V#x0yXx3*!iD$TgMSv+r~aYDAeHL0xE(DI5N zGwfff?WEszFRV)ak@_=*FKviSaWa)OYcHoLDJ;QY)Kw+=5~0LErZAZzWQwi|cPufc zu=v)eWQyS=`P?|l{rlYhb?h+>^{APgH^$%9oPCs^B-GW-RhsWNj^-rtE$TnjS zi{`!(CH4}$sj5YuO*>26B_4kHo+&}5WOKLax@f9U7u{46(Ai3YB_WQkGtgT!+98;Z zUN8sUXgzwoUQnnP45Fk=PNHj%ugH{SEjx;TjZdO?a&mJ1(cCN0=+qUQaYMFgidbGZ zBP%jK^qNr~-!OlEQ**(ccAv>yn=I}YSv-lvW zzos|TFF^FgUJk0o*BG6M_#6kH#E=rTE6Z_~y;(9gi_ISB+t4#eb=l+oz280N`v3czf1IG(*<67A8~M!2dIeUM_pE4^o0VqMs@{G2 zHk%QXikpjY%dYN%PhwBv8hdoqxMAZtBg5-zIfiJ>>3@90t9@j`hzX6gv;I!K$!$Gg zNP2Lywb{kTuB;BM99D%VAoi8R4{UZcJNc*q>|NV4cgfCg_`6pVC%osk;}=Fh|Tb>*0`xFn;qN+HGg3Dfr6>I`jYs9n5j z{KT=i*4e*9HuYS&(6gt46jKgI)ctSit~_GwUVe&CA2}`O#>ykd;-5#=A`t(>wi)Wz zYvs{MzL%ftj5>$TuS@DW>B@C|bR%>lb%*K3>E`Pe>XztE*PW}oN_VyHTHW=!HM+ZW z8+1?Vp3*&|drtR)?j_ypx{q{U>UQYw#Al4{(lXFrL)0{-_1 z-3vGHT|57MWWn(_7Mw0th>Hs=3!iGfmDLzi~}>kOfVZ91LlBvU;$_V zP2hBJCO8``2j_tcz(wE^a2dD)+zB25-|BQ;59kL@1eb%g;BN35*aWtMAHYxG7l8cY z1sOUo^6ULmJ$+vx{x1OR%ZKvt1waTyKnx^63UmOSKo@WTKpFY!z#?!ixC$U|z9+z| z;C=8V_zIxBe8{iwdw~4-{s4dJbbgeXA7$n@013#TD>wwyfa3tp*}odx4zPbe&e4Al zxEG)t{Eq<~)4vhmI{BXkIB!3$PrwY2??46U1$u+NU?>;~CV->CEP!hfK)DC51XqJ= z!3|&~!0`i*0_;2R8TbNh)9E^5{~e0~%A;d7z%}i-8N3H@o*j4Tbe-Tsry_vQbwU|; zLK$~L8FxY%cZvXR2{2Pg-~YbWHh6Y|*!K6W}Bz>iMngEe3Sz%e>~2#|+P+rc;B zJFo-b`gX$g?ewQk*BSbDE(Ex~or9nf91l>YopElRSAiSB&EPI@KR_9FehJ_hopB92 ze-3cIopG$rIHxYSW?hWH4x9i!bm<0Ao?WJZqX5dZ%M36R%mwoSu4R`-un?eZyF3A~ z@2)Z^1p@)fu{ZXguW(6qwZYbMsDBEr*+wO3n`@vumz`na<-`#6KEtn3@1Q&vfz$M@sum;=) z?f`4SJ>Xuj8GH!fMt9_)`!?_`_#U9ly8oopm6}0!FaV4N;{ndC6z5ioXXPlDa$KKs?6>?guuG@wiGB7=fE4Heu%DiA zxF;O$iF53UbL`m@V4pp4K0W7wGr&~<`|7zKAg?_i1P=q0bI->C^4t?;SAo1%n1BV? zfCChPVgLs#P?i-qPDL-!2lNAQqGA%jwXawTP%afHlZv~*-C!NK4?GE81)IR@U<-H` zd|Fx+E!MH%$PvHPOT`=ZSI zqRjiE%=_Zlec@Bz!C(S79b61<2G~d6Tfyz%POui>xP5WlzBq2*`@w?%<pB}`)aDeYtzjMLe0BQUEj3$5!z=8hASN}l(dFzkz z>5o{^e;hzQ`=gxtqn!Gqocg1j`quz>-+ww-02;wU0O$LoeEKf|SAm-V&Z$4nsXxxC z|2lx{+J6Ih06Y!e0LXX$t>7boeE0tbd@#3hclQP{sq`?f~R- zz#MQKI18XW2jJKPaO?p%_5hUU0F>u|djZOG0LpU!%5eb7aRAC<0LpOy%5eb7aRBl& z;0y2r_zC<1c7ol2^MrUY&;%^N1{?s_c_6Oyz}}!Q=nn>h5#SJTC>RZ zI3FO-15t(pQHBFg0n5R8-~w=wPB#di47wOx3N8m%f*S$KaL_~G5%3sz0&D~**Fn#M z=fR8MW$+334B)&5Z3ElEH{d(41N;bn2ET$`I^6+o&EkJQ>^ongD^*z!~6dfb$)U^BtT4xHf}vPJ?ky zgKNbfakyq0M}^n``~kcJP*co8I0>P_;;Od2wWKgSB4mX1aJ;RI)g(1@;LyUH672qmxHMka_JcgvfDsUsX8>|EO zfeqkQunBAh9|4sAkk7!^U>Eoe`~m*b>4sW>9|S=dL_tS@@*mm<^aBIHLEvC85{v?q zzzl%$9*XiFdW=q2iE^$)-Yb#!O60wA8MqK2kCiurHQ-ioJGc|91^0k^!Fq5%fG?HE ze z5KswlU8>+r)kJ`6QH5(!g=1#{tr~e7E&=3kxCy|Q;eG&LhQpWPQP2&P0_1&oPk=HWj(iWV0>i;LFcC}! zhXb6)aJVuYWjh>YJN$UC3|#sDQE-=0S{7OxfS(rx>6DNVL_&}dMMAoVm>Ft_p@#va zyQRCOyQF&n1H?Qi4T5yHgoGd=eJ+1o3-NsK``r89`iRGY(m z7V#yzt+ok$R&yuS+)1@x*~xD9qR(n>q}myDTJ09Mk*}J3)n4*C2&#vWv3e@fl8y|x zjp}Zry4$F(+v*>q*Xq@%NhEcMLZ8)J5=$G}q2KD}sy>LZxQXf;khS`E{J_ubU_S>r zgifm;Mu!n2YXexXT)g(O(Vy z)mXvNAgK8U=BwF)@p#v2-U)(m??||Ph37{H;UDn{#i&6&8sVP8n`8cPxx#y4kKqF_ zd-zDkFph~#W&v(1TnFKH7XCYDxx$~^mcq`Z;xM#>v0Z)ABYQI+cGF|rlzD6$!ktyzc2wS?ZdluG_6Uim^;!GE5D*_bYv|90?y}*Vn4@7+QWJAD?al-iu?jcZ)UKLt;cM)^>2K`zUxn+fnO!w2OcC_c z%po?Dy;*B~Uo$&vW=GA&^9?`YJDT~9X1n+UyJ~h7JvEc7**zX0U$ZAc(EJS&l8B^K zL0`?I@Vw^HLC~TYm8gLnE$pd)faV*jvl2Pwch zinVND6JPNy-|+)KvxA*M5IdQv%wRV2SjZBVv63~|ZLIepb_;eKYsay69P6%Q-F575 z*mLYY4sw{IoZvL)xX2a$VsK3 z4PX$5u**&txWv^U=~aQUpP_tmGpo2ppO~* z{P(9B`_!gh5cF+C8$QFFeeJhjb2`!)yY6S#{g-1u{lDTHwgtfedl_(&)0{;YpZojg zvVLwapWozm5DY9%WvWt*n&@SaUIyu9kX{C*;0PDFj6MhXj=`^kU`R6j=R;CqpF{og z(9Gy;Xg1vau%g)CFwYt0Im666ygv3fyftkx-v~E4Vlq>h#>^lXIiJ<6Wj%30Fv{OY znRC=uzT<}=7_Fnxy>JVo`|)`YjOm7Z7&8RlJ!WJOjJ3P5ZfdN)$5ue5ae5x7=W)Jc zoE+oyJnlzyIPL(y^G6VjxAXCKKHkp9U*kp)Ot_1?p70WVOpF%kQrN?k8iZ3T2&P8Rn5Hx*CJ3f^@28n>S`W-UtuK0*wwL`J z+;<^1=j`~KjJx(C6Ry7_V> zqZ!MDAXvJ9HLPO;n}T53mzZhUfB(D%vn*eMe_sAI-{Rg@tj2$~!u_rI@9%nF`6h3X zo{VG;f>lK*Pem#d76hwhUM=%#nODoaTIMyMBiEYoOyr9oSo;a)Uu*ugRj3vO>sn); zbv@}#zaUuOjX?}y80OqCi)F~ZVHNhZaVJMO#tBXbL7aWW*+-mx#MwujeQZub2HwUD zo8Jk7EjcNSy=;+dOL5%(mPh#f7N6hpA_%_n_pjse1_?>bW`5!qb|A+$dy(OrQ=H*^ z5Pa)izxB`Gp5p?SgJ7$F-YVnP+uY@T5NwlSo7>o?n{B$;<~FwJZQE?-;;y$X3WD#J zV6Wf#dGVbL-+dhf+jX)1zdyfa8{Y@P_y5_$J`Qjw2!6PVXZ`RGX8PgZAo$Tg8zcD1 zd_S4*C;R@{-+xX{N>XG0zhomn1^Ezp|5uK1BB@QiAlTs+c0|#DMl=b6Uwbi(5sYGN z5d78$fB((je;b2YcP_#~3r~YSj+vWRq``qsAltt#aeS3Xw z?<#h2l{@^6``P;l@7TUKNsJlxnPH#K_vw6}cWvLh<@@f0_5H=_x@za zygvwSL%2C#r%xE=%t%zD5)2h4Jy4PEF?FZ!VW17nf@fcyvKKj7{T z==^{?Ij|hP9x%g!4a8xN1Md8Q+y~@7pzi}Wxy?Q92f;!456XW~=7YLEDEGmPxRrx> z$WK8EQE(7 z?BL*ce2?xA{u>0pXTdXnk6{e!*vG9PIP@l|NK1O;Kjcmh>GMzlKICKMKUADgF~gy1 z)FhHRL}53FdLsKF@8%)TIy9ayn2Np+&0+=eAKJ`M{K`)DpwvT$IKnaXen{7c6OtHR zAJ+5XG^9h`!*1iS`#vo9;hgCCu#AVze7GDHs7zI=Bllss57(wHU75@lJoE6=AowF2 z717xr=J{hGdjDe$>)FUwenI{}cCnWO{LW#_@W(~2@FzF9&D|h4k`&pGWW}?N|g^>S9dE_`!izsw_#N8Zej%-I-)0W;0XEyVY_s9~KA@>ovkH~!_4s#y)1~+g- z-$(R)e-ug41GMvj$6_s1$w zgL=q*tPxF+|5!^}VTNPf=|x|>1IGq21n>DV*^lY_*e1SW8{7GjpV9X*`H!7J?qj#O z$9*1RpU0l_DhNakj;F*saa`8pMJR^M$7Mb)^KpG2H{cp?dU)!+|6;h zkM~6X$NM4s@qx@m&g1eNe;ouT-oy8u@VOIuJF%AC9Ofu`KXD3upZE(ma^i3PLANKK z1i{HSc#|X~ClzTZgnK{fR!+)(QudQNKN&%7>Jo#VPs)3;53-*8oS}?hG-Gi;Cztab zKcL@}JJ`t{_VYXXK6#9j+(Fip4|vF9o}%-UFERhAc*uV$A-Xu_E>5+<&xlj&@O`Iz z?sPheAouBLn$iOKPwV}(u20KT z2&YeRhI8CT=ci@%uYxo3o=JeN&mK<0DjxQOiMWIw0xbFYHne1Oi+yOHzqp4a<%y`N8k4$h|~ z9Umdeo_95$ zmc-JQ_H?2vJ?M=)zvyNz4rV$sUYx@`7O2JGPCtsuCh!%LodsUCW` z=a+SUS@z4_aVwYm zAot}#3`O^sr=sV}o_~2Qap?B)*L=tK{KPLD!mV7^>*YuMi(9$;DhRHG(DM~{az)-N z`o5BiT*!DOANkSsmBJLE7$qo$+*iuc6dAAR@XG(N)2qqQ)zwHkGakKP)%(@C%tzN( z^?P*_U-2#SUzPvrkLdmCK@M}26P&`&w`=jy^R=YNeJu^?$VevK$u-%peS*x_Dp8FZ zL{Jy+=(R>PragU_fP22C<7+dRjT^b9>uXC`hWog-1|45B@3mjq$!=u6Ci69!uN~ny zCppcNAow#qpVEXOtY9xUgW$S(uIv7KLG*oH-`9&$mN2SQ6Zx;#q7Kc8p*5e;0rzu# z9JA2#^+m{j-LtN*W-aT{^K~;^m;1U5*H3Vk^IXCnuixM=?(iZAZY1U%-X$k_$VUO} z`^Lw}e8Y|0C`E1RQJ;oH<6dsK^BZ#Ch@~y%Ut6+y1i+JoB!hWZ@vnGTOr;cA@3pkEw^&Zvu@eXt+JG-5><#o z{#$y!)t-)Yp(nlR#{l$xOYgVVv60Pu%~rPaBfsz~a^KSXEqQOrd+RDXzoqkA^4>E4 zt$W<(A&)V`U+Higf64QgPX1bm@B7Q=Zof%x{4BZcR&Gb)PHx-5ZN1-agRXDOe_Q_B z-7&*$Gu-yG<@PAXGJ(lVVFR+?{+S)<{I=Y;5AZvOxriBV-$T~hvfh4*u8k4giBAIF z!tLBCN(tP^9bMn4KxM+Hfg8V58@cbudq>_oo#~3qcY4tmo!=SA5QZ^=CCGY5pLY|I zk6M`X?lkP=uH1J|a)$HBfA=O2c!ZwsK1Y5d1^42Sk~HZ5UPdyL758$lD*C=B_dU7q z)u$ni(fd95?{%Rsc6M(xI=(jv9p9VDZ050mb!_7x`n`7)@8`YKoI~DwSNIdT@7)f9 zzeBu%ng32i5|ShL->FGUdSw4Q6K?%)IscaD@A>HLZ{K&{=kDjlF7CVc`+C3M4gKBk z&0xkb9{KOfe}6hNF~j}2tYi)AiDL_2^9SzzzTMpa?^&|nzsukJgYF-g;ek7T@D^{Q z=Lhfb9=UiQJAL4O9#lcc51P@ESlZH_PPmr`J&^lBKjeKN?}KT~z`OcD-Um8=u$V7d zj{FZ+vy*E<@K0hsAd+6pVJmj>&qH1Yfj@$W?)+f_Qjh`pAIkqQE7@@S4+~P5A{66O zyax{((S{Dl{!sRZp7pRV0~m;#dFa^>7b5S&rL1Bt8_@N`pV-eO^!)HTx446zAL{wx zW1jMY*Fo?|*N^0VB<~}6AIbYDJ2}WnZrsEp9Xu*Pb=onJjU2)EJ@&cBW_fHUkL7+m zlo5<(EK`}s0_19^y6~|GmMeAk02?A9GPZN_2@8?tbpJw7cbp6zgKh^b9T|YI$ zQ!_j*LwPDu6+3uZ6MJ|n`_lmoWC(IU^^QIrj~zXokNi*NeJblyS)YExc7Eg+b|Cvx zeLsDOa-Tj!&;AIW#U~+hKa=~J+|SaW>u0)tmLIqM>_a|A-_MHkDWxfk{Lj3r&*Xfz z1kZeSJqVsB$BfTw(S-@jU^equfX<(9WHWkxz7_eO|G-b|=XcET{1_)WjX7Stf!r_T zevyK-q$eYp$cy|hKA{5oeNl~?)TS==X-HdoGL{KUW-9W&n2o$Iyq_=3_hK0<`5qZx z==p`2U;M^y_OhRY9OekJzjzP?FH#yW~CHJdB=IA1a%X#kbEC^nwBn|1vNM_#QU2>8KH}kpx`hG3%Yk6N+qXzQ6*86L{zmB3I(KNw3 z`dZf4I(>aU2nF$YpPF=F94m=q3*WGnU)alj4swV;ILalia-Cb;;a(65CF5=0;a%Rt zvqB$GfI^g^JQ36-iiR|$IWff2gCWddHuG4>5|$xzXbtO;JtTW*H~Toi?;J+n&Yq$R2+)U-K>7FhhJZ#6QV7E+A`sUB|!4ZSL|i2)&VnY~&yp@ACl# zDNGTH@hPRLgS>Avpb?Fc_l=gA|BW`ZL;g29F^<*f^9}n=kQO~8u&V^0VLmu-l&-pLA`*|}9C25XlzPTLxdsAPDQc!^ExRpfp(R-rC=sS^)6LqCK zz377(5{+Uk6PV0Yrn3pz6YbzP+)5(36a9|P6CFj@iT>mtWKE>!M6xE1#~Zv!Vlt8o zw~@Fs<*0~`6IY`qk<>xwi5ntsVtEtGn^@n8dn0dRohKf|5Qa07(JVvO#P*)VGn42d zi5`-eGl_R0iJc^oJINW&a|!vA=sn3JIDE^Q8Jt+Kd*&;9io-pVYpR>N@Ed#^YX+PGttOSiu(boYYQ}9^^1bIl*bpaS^$b z>OHBvN##uzpz~xpPbP1&BqYO4Buh@-I!)=BDa+FqbEaIw9^_7Wj|aG!l=7$2eX7JHB{?ZELn@u8%FcV_CNJhl zRgfCE@l>*>@-C-xC#gIumF%fxPt}=$3_<2p@}`nEmAt9uvydg|JJn`>!kwg&Kb5Xi zo#P@`kU7;&ZXE6Y?q%%XhkNAY*m?2#m%3+Rl?U6g3-05_lt{?hNHwZgQH<_tS$DO2G!75};7sqD4 zM%U?fa)cY`Io)0E^AJ6!d&bKk)1L`KeveEjgE=!)!cH>Conb5!kl*iv31x668I~e{23==Z$3`}>1v6y$ zAHQJ-8TN6IL)=033_8!K^Neqhm}I0t_ZhPxf5t)-p(rKLb;fd3q%!qrNpEzWQP&v< zGmMdpVLX$NJEPt+%9~N%j2qB-MxAGrH>3G8Zeu$?@-t@0c!5_z=xur4*2&wS;rrh9 zxwjAVcM!_t=SwE{p6PAeOeQpF8v z(vXgfWJd1H?;>wzc{7)!G-Z)Dv-vYur5ZJfpcb8wHFF%EnfY-L%A$uX=FHNZLCBqD z87oc8C|~968HJeT7JiVvL(lRn$5jr(|iqANY;?D`xwFfiUGD6q&~}+`|kx{s}_wrJ@k>yw{64_`dgiE@wRKC1)9`Qk`%j(S6RA z=sc$xa+)D$J37!8-R2y`P)0C{rO2Pt`bXH zKISRUgHWy{WFSBC=lY0GD2~2!$(*Y^m5@D`?75l~Lo97@C%NR!)rl_XK9}xu={}bk za?Ri?0J=YD`0a+@Jfd=iqFWTYfD z?k11ydCF0N%E+CkCXv*}&E(N}p04zw5B(X8uJepw6td^}61Sa4&v|~}XXMSZlRe0t zNA5gw=Q)PH^V~t+Jnkcp`^fWO-hVNFo)^3hLhpw#!~5AOi#+d-WHr9;eV@ylhQhe_ zybXw^DRz)oe|fv1>%8*kl|S!5%#ha%c_%T2>C9p-^KtKaWzV~h0~|u`yeBx#S^R9t zdlxt2zt#%ni$?<7OFmuaOG#>E&sP9F=hJh(Flr!gzS`77?tF6RlRIAv^qtRLtzV8E{`(OdzbBfDc;|6x{f&M;tfv)rG zI{zEEm;8xHM@BN^9`nD;dz2%bI>?@1cE49Fl)o7*v7`LmF+=`g$eMpFvgX%y{%Oo) zHY@oGH?I(jtF>4Ctaj zUHaf>PJth|5`+rANp9?o(s)j7UnKApGC-BXeldLh3tiP@n;bFFbSUdVJ&(y7w^J{cJbjO zUQ9scGY9`lqJxS5aQk$_Cd`%yODmu&D zNKd>6MRZ+cAVV0=D8{l7dHwFRP!XLM(RmS_7m>G!-izqHh~E7!wNR0*9OGdS`os-< z;+db=>n9^{SD)iAQ6J`JZEzVB0?`}8zVgHXxzWFrT;$is(}K-VSBP|^$~-Al=e)S@o+X+#s6F#!2X z>bj&GDLEC-Dk*zOotM?Q>-{%(c``kjM^j>N#@|60We}YhH z-&fk_N}H#&S^TcHQ0XNsVHwcwYjyz@UxojVNUs<0kYo4;NgHSoy z%ej?u@8h=06`&|((Rn$Ym#d1-%jvvaLmJbJmc-JA;e5diWG^SX-_I5*w*4E=*j0tLj6&xX*0B-yQsFCfUtuTmS8(eU zbnSPvh5U}TP=!lex!@VF>F&XZp;yb*H+!gg*QQsByU9k}ISCqeE1a?(13OOq_ zr8zOg(t{z)U^equ$P$*Zk~OR+jxD&2in^|N0C_9Ajf(R6-Eg6br*PvH&*LU4UdCNi zlC_fkSMtnCW7vQ>E8P!5mA$)_<*w{bDwm)X@>kY*yMl9UbV5+o7BfHA3bvdBgM^CU2OI!}`#l&l!)q@w?bUVR7g<>>IZ6JwNe3e#6~_ zxtlPV!>(`*orm2-?_u|NfDXds4|~e%)%3ZVi?NHEXVH7j8|bg*9Uk*K2!+Q({&4xjlVXN&GlXX$ z8*V2&7w_Xe2(OCl;qD~dZo-=(cX(?)qdj^KcPHU`4xhvqOvBBD&t(CNkUe}mIu1X= zaZVv`_ysN_cevc)a);jyLJ|6oNQk@MLqrK0B2UCZ++~FC zi}bn352#LCy3&K**g>TJBFCZYNckh>kDQ4aBA2s@wU{At6I(DxPy^lnDF^T^xC z9ce$2{{*30@koFhsg;4Zk+asjxR+YFc^`YMRf$G4p*b<=xz=ZNpfla*Ngv#FEq76C z3i8&PfxNZmVfI??q1IC5ueFk2xe|nGzlry$b~rtl#Wx(|0nc&kbwcRBj_&H{xlTs( zTqi4TrH&cun4!*xd`waFU#Apha4&UauhWSxbVu$w{Taw$CLw*?w zHuE*#vXdj+zL-XS|V$Vnc|U)MdB@9;QulNas^|Oa`CPq<*hxLP>y2SN^4I%nOX7ibl^-dXDNvUj{IUp^RWO z?mTKD@X)V^zOTN|)!)m_Ak;wT4N{T@ zH`5>kx^Iw|{1l`x?xn#eRG>0p)F6Udbi$o9&~*dZ8_3>ZEIMy637t1sgc%yRlLoRj zu&)NPHqdp0pV`509OV*^dCCi32cd?#_WS5U4HJ=+6r|=YY|Yz8kw_E9l9ZRqgl*l0rEFm#U|u$r0YiC@dH2c3kNxj z85*77G-okKw63G&j!sT0^d0S9qU|R-EAmGdLe^+GqvedQf}Z`}x=?g&>Jmd2bR2D; z(e5MKeMIXxdKxpC!+d0p)_Jt7(XvK=kG`Yz9j))^o$SUvL?7UHW5O}FEj%|hhCoXy(f?wiToY$Kcb8u^>)yxAV)Z>HyF ze{hTwT;)2qxWnH(2tv(MqUYxCB6oASo9nuHLF}fvdu^`k=DKb!YjZi9%h|jMEs3Qq z?U1{E>I0L`lk^`<4}{NfZrnCoP-O95b}+OgDPchyHxd9As~~mi5FT zcgt`2j_=vWN$jcR1ui3J%bVQhE-!;nOcJt@gIv6io@4YJqvx0+6ysA$qw5%XV;Z3E z7g zm(X`BeYbkRBmU(%uLA$`TC$RlLdYH~d#q>0mO|&T<%pyS^2WA8-dI^-*9Z=&~Dy~n!o*2&3F zEj+XJOzf?-yK4P92(@{Kl2pP?wW&@`bl;{K^0$${jr?u=ENRmoH`2z9v>C_{hBJ~c zk-g1Ve8V>6Zu2uc_>H5S;3~4V`3qUw{DZFB=(^3bAk;Q7>2V`%3!>+?dT#4R+Paap zrO|WSid3N*^0t+?t-Nhp(-wK#x{tOxZ)^Uxy^z0cKXlPn$8GiL_tAwubDy78rX6Eg ziCg*1O?`HVBOK#Ay8i4IchK`^@_#0OyLcoZ5lKlwDheQXyRuY3-|b{>r|WhR)S@{t zbfG7`k+a<(^xRI*?M5=4CFr=Fj@#L1yPx?=s_>sM@M-(e$F6t-%Gnp9hb2Kc{(M=ZaewD zPCnOZCSUUhXE@I#uAu);kI;E1GjuXTropd!rS2J|gdsn@8 zorqiMIt|@+HAmNZY{jj2mA&hJe#f)A%HCD>uDb7f3z@sV;8hUnCT}-cyUE(kyV)%{ zS;$Kn$|HX_x6-XT;kcD|_sm?xE)%e{hVG z=()#vE^!rkd+57|yglXZ84r1TzDZ*A-ZKTMFhkEmL?BPk>DX&e-`C6Mdc8|In$m`L zbfhzV7=rh**GR@NjtQ8f*E|-o1atIS$!g5f>j<*X-_AHA#d-|jKzKQmbdp5%-?$^bCAFH z0>0xEFN08@Y*a)KeI~Mweca$a4{`5(?4Ymy`s%uG3R3eH^7oa$Z)V=-0}4`@A{51~ z_jMzETO+sMH5%&Mg>Ll3&G(hRufF@bk-qM??|c@a=e{e@bKkYd-gg&gaoc_M-1i#t z_Wg^y$lX`&zH;|{7KHlgx}UE5$=feI8IiYNR?OeeP4vr2Zp_fHGCJ-jPro%B#P{|0 zx&FndPY*t4F#7L50{!)$iLU$Wy1!fLznCxC$Y#D~E8F>j(_H5^_mI8+WAxqsId(K4 z8D<#ZMh3__;5}p=pz8tdWx$7gM0p};MH}pNKu5aJonG{10D~BcyaVJNAn$+$=zM^@ z1D3N2^AA{$`~xZ0dC@(i-$ zL1%-|VBa^`=LT0M7M%|s$3*;G96S}>4_?Mf`;a6gCnfeY#0*1pKE$02`2;sSy!flS!J zuxz|fVLrwT!^|+u%?v9^7&VBXHub1a59A*eb{vDY1ne~JnUQC$uN0` z$vW&;^gYbo3_HP9+{rL^GEDyA_BveG!`;bnH$GhE;i-8G*@x$+5Hb&!dAQ8Oi=+49 zr6_~$hgU=o!}UIVDDn*7#a}^agzp>Sb0f?%!Ym`)%ZNG5XAw)#|A;MojTuImVZ?TR zU@r$a#1W2jl1D*kr2He_BnipztdX*hOixDgP=pfbc%-}|WgRK&NPUm2P9xed06$Mg z%0F@hx*j=>iO4*18oC}S`^XJ!LgtY&kCb_&I~ghO$e;NizoCPXZhhpRL1 zAopmwN6%vci}@1yM}NgHxRKFrWb{7tJlYM9KE?@TAN@}d8skRBxREh#WQ?B2$U7zj znUH&o++*Y(lN()+(e)U4$5g<(IY!yo(G``_AsFsI-lT1Cg^TL7`1U96Wqsy z=D3duI-Ss#p7fzV0~x|Fyq6Q!;YKFNJwfgXx}NX@Kl4B2pCJDPnJ36NL9Y|;^N^?f zm+4gyni!ChEEJ{)a!&k|(#She-ih)~tcLj}MiPsR6WgKZiF%&c6}K|67jjROd!p_q z4q_hPaXtu5^2|v&vAapSnlusfOxlCnnB=x6>3q^@bUo=d@=toeBmU)C5SsiZNk~pA z(vpskC`%>eo-Fs|2x?Q0`sjGF8<{NYWH~3xIoW$Tc?6>w#{}e_yb9e;*6rjS>_pbd z`}rN2C(Arp=E-OHn}3jX@)Ptu`30|o&=>J|1KGbwjCb}6ck@M6^!SA?zSzVG>}X0R zN+9!;=D3e3vQKG?zNhqK00WVK%20;$1=E{C2z$|=rbKU41T zI0#LRPa?(8@Z=`f;~L|uC zo{3CmD$|jD>K0_2D$lfxl*0E-^SNou`ISrDLhfn0pY{OVP1p1EgqUHv8K#?IdP=g8 zjU42{9Mkh*2h-ihblIoNKD`;OXoKw2+tUxvo-Xfnd8g}n`V3|~jka^Z;bU^l5vd_}@EH^T1 zJUXA{MrO%7OYgI0qxV@0kbjn+@3Vg7To9Ta;yvtjb|Cp8Y`RB+#Cm#j)kdG-!aiWlWj`wj+dpaWX9DUE}gL|2y?>Vy1k#&xobL5<( z=Q%4`!+JI%_nduPdEPKaBKy2?Ok+N>&y#(g8=2=u=E*IicyL(l&2zfXiiUbJHI~z z8NzVf$$WP*e*%-4ijL>YIDZ`*F!TH^e2v`mxA8qcBK!Pvya+-If#_g?m}(E*9!|k=tM7=ij0?NkVc`krwx|=xyX( zRG5$X1f4JXl+u(%?~5u?1^E}XW(4-W$TJt|VzC|;n{jaidNYmrxRb?SvJCgV_#5P3 zydC)$>w2*n7VC8J9~|Q(XE?{RAhbmGCCNxZYUEy$k<4TzKP7M@OUmI!mdLrJI^jgp zj1COJjVu|38(E^~C3;?>=Or_k%{&&O>m~9ok#~u{m$;85KOyguU)jkX_Hlq)LFmiG z6u>jT?77n`IowtrB$hiPM1d0lorG=7}=Lj zLDx%XBKOh-EJo)`H}NAoa3f3I$Wl3%>UycJmmcK`e+Qvu2}p#SUZ&?|dR}Iy%iQ*| zOz3%8cHW~n@-8cl`&i~amQ})iEYtfky)V=IG94_dO=l(|&$1&t2|~+#-*TT@Zl2|4 zS?*SrFJ~2NS�Q>wCGrm+O1^F7&-z-^)*OhVxwFDt`u{74dQ3E7BqR3fWg=L+2}W zz9Khnd_^&2UQvx2L{OI~8lvwN?dZ*TCNYKS%wjIOUZLw1OIg8c^u6L2cA)bWGOzHC ztkC<4L+E|QF;3uJUGX>wt(0}8`(4=>U98l@N^`Ef5rkH~iQKCS@F5=~|0=h#%6+WT z^{Q}cA^$4*S2ZA(wzQ`cUFnWnU#06+OIU{7tMt8U1NO6O3;JFq`zl#i$+=3-Rql6{ zo>yJvIyd<@2(3b!U_R~OsODoJamOSNNNM z(EXaHyx>(3TAP{oDS+H-$N&w zyOK4mCk`F2{f2FPj~idB^R>EOdz!PzyY?dTuKg3Uul4EC_8#OnN>*{tbmGLNPu?<_+bji0m6=-_VSf zw8Cv{(D?>=H*}&4df%Xf4ZZ1$yVxM>2K(ROnH%4s66V}Enia^s(VcAkoj;I&<2nAs zySMQcw=u&;oo{>@gyI6?lMr*nCB@CeeS++9?j)`(o)ss1oa}Kmh(_i(cM{hbdE;b_ zlQnJt`i`5x95%2C`QyIjJAOddaWcp4WDl~(x#>84$H^QgbDYd^caS&Ejl@0V2~T+* zgf?YF&zlNx7V7|l~e$I(u@*}*I5Jo*|3ILIMBLf`dfueaaz z$Iu7)>pxFFMsNuWd4LGctM|FsSFrmrxnpzi9gWE!y9S-dZbkmsa#rv=?!gSPN6~-m zNjCBfo5&)2Oy9AW(RWPl*lzZ)4}Hh<9Y2=7=sK?J_=%jvDGWyT__<8tGNv#MdE-}b zC345*j>{dN&mGw7xV-U|=sYfO+&;w3A78^mJd7FQ^;D3j;meH0c?~|-@Ml`FFAZ<= z9`>cd8#L%I(TC4shJ+asc0SRcA$*N*Fr3plgYn3pn87S& z6U7|KUC5o>%g1-UgU*vWPwG6?8~Ic6r{qn^nvykjDnl8Lu2b@*Ml+6?=sEREu3{c~ zPF=@hZsZo0A#Y0Fl)NcDQ0#m=O^#aWEx9K1vNe5NCRdOizTguBwRr@PXCuf$lmltPDJJ=nVV#88iKq{cD!jA zr=f$UGr5F$+{+7;`7jh@%$YGuW(IO+?&NM(vWhjVN8g!0@-*^i^U0jTaO_C4uA6n;Jc@G}%@`)4@8&DGk~#c}tFi0N zH*pKgLczBA`2DuqSoBRobuUFbGzAF}o#D_izB^q2iEV{w1h{n-WB z)9hm0n{{t?3GU7Q2K{C4!`^1ym33Fvo@W1qch2f2dn6R(>|D-Vxha?_XO`Smc%z&% zbI!{-FXz16Z}Aqn-{b7udLHLVHim*0f39UU-nPYzE$(e8v6H>L!M}Ky4>-WVP|zwv zt2tZy(vSWOz)rOeVjOyG_1>)&J_-f-p?IUbH_DG>6c;m@sr-z~nTdJwzs4DP^W^2s z--UVd-Xnhx58^HIb}1jBn;!lb3JUTRMsNWWn8+k9MP~(f6lO7-Ygvf5DO``c3M+6= zVKsUyc#DF&3i>NNfp;lv=V&NsGgI3+oQHR5^X6@r;eFbs;qBYp*|rY7w{0d&Jq;w; zMhkh0v}2w&^Azn?aWMKTeiL&Q&%}L2{S|#bi)Jgjv*^yEJB#it>ab`hiVHAbaS?W} zcmp@FfjGNDLCJfToL_QQ$r&YQl$=qT!CZX4q??lOap^f^F3DUf;eAUlBWvkZ_F`|^ z2QiG(ID>CElomGAqvy?aSA}MrKc1O9& zPHLE;Y=*KK%CGYlM?yijo$US$_NMzd`qGd73}7H9^L5PEJq5YCZ(|J`h@h`-_f>qp z;&w%pKf?^J~tpJ%C-Qt;Ji_Ht{TWzV-ro ZuK9=I$3J@a`sCMPQ$G3i)1QM{^#2g>4@&?5 diff --git a/Everyday.xcodeproj/xcuserdata/mk126.xcuserdatad/xcschemes/xcschememanagement.plist b/Everyday.xcodeproj/xcuserdata/mk126.xcuserdatad/xcschemes/xcschememanagement.plist index 6d3df0c..dea58b3 100644 --- a/Everyday.xcodeproj/xcuserdata/mk126.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Everyday.xcodeproj/xcuserdata/mk126.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,19 +9,40 @@ orderHint 0 - Promises (Playground) 1.xcscheme + Playground (Playground) 1.xcscheme + + isShown + + orderHint + 5 + + Playground (Playground) 2.xcscheme + + isShown + + orderHint + 6 + + Playground (Playground).xcscheme isShown orderHint 4 + Promises (Playground) 1.xcscheme + + isShown + + orderHint + 2 + Promises (Playground) 2.xcscheme isShown orderHint - 5 + 3 Promises (Playground) 3.xcscheme @@ -49,7 +70,7 @@ isShown orderHint - 2 + 0 diff --git a/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift b/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift index fb70067..818ea92 100644 --- a/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift +++ b/Everyday/Modules/Authorization/OnBoarding/ProfileAcknowledgement/ProfileAcknowledgementView.swift @@ -1,4 +1,4 @@ - import SwiftUI +import SwiftUI struct ProfileAcknowledgementView: View { diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadRouter.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadRouter.swift index 73919ab..d8b984a 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadRouter.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadRouter.swift @@ -12,16 +12,15 @@ final class NotepadRouter { weak var viewController: NotepadViewController? } -extension NotepadRouter: NotepadRouterInput { +extension NotepadRouter: NotepadRouterInput { func openTraining(with trainingContext: TrainingContext) { - guard - let viewController = viewController, - let navigationController = viewController.navigationController - else { - return + if let windowScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene, + let window = windowScene.windows.first(where: { $0.isKeyWindow }) { + let viewController = TrainingContainer.assemble(with: trainingContext).viewController + viewController.modalPresentationStyle = .fullScreen + UIView.transition(with: window, duration: 0.5, options: [.transitionCrossDissolve], animations: { + window.rootViewController = viewController + }, completion: nil) } - - let trainingContainer = TrainingContainer.assemble(with: trainingContext) - navigationController.pushViewController(trainingContainer.viewController, animated: true) } } diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift index 45f77e3..62ada35 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift @@ -14,15 +14,14 @@ final class TrainingRouter { extension TrainingRouter: TrainingRouterInput { func openExercise(with exerciseContext: ExerciseContext) { - guard - let viewController = viewController, - let navigationController = viewController.navigationController - else { - return + if let windowScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene, + let window = windowScene.windows.first(where: { $0.isKeyWindow }) { + let viewController = ExerciseContainer.assemble(with: exerciseContext).viewController + viewController.modalPresentationStyle = .fullScreen + UIView.transition(with: window, duration: 0.5, options: [.transitionCrossDissolve], animations: { + window.rootViewController = viewController + }, completion: nil) } - - let exerciseContainer = ExerciseContainer.assemble(with: exerciseContext) - navigationController.pushViewController(exerciseContainer.viewController, animated: true) } func showResults(with resultsContext: ResultsContext) { @@ -37,14 +36,13 @@ extension TrainingRouter: TrainingRouterInput { } func openExtra() { - guard - let viewController = viewController, - let navigationController = viewController.navigationController - else { - return + if let windowScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene, + let window = windowScene.windows.first(where: { $0.isKeyWindow }) { + let viewController = ExtraContainer.assemble(with: .init()).viewController + viewController.modalPresentationStyle = .fullScreen + UIView.transition(with: window, duration: 0.5, options: [.transitionCrossDissolve], animations: { + window.rootViewController = viewController + }, completion: nil) } - - let extraContainer = ExtraContainer.assemble(with: .init()) - navigationController.pushViewController(extraContainer.viewController, animated: true) } } diff --git a/Everyday/Support/GoogleService-Info.plist b/Everyday/Support/GoogleService-Info.plist index 2ef3827..170c18e 100644 --- a/Everyday/Support/GoogleService-Info.plist +++ b/Everyday/Support/GoogleService-Info.plist @@ -9,22 +9,22 @@ PLIST_VERSION 1 BUNDLE_ID - ru.tech.Everyday + ru.Everyday PROJECT_ID everyday-5683d STORAGE_BUCKET everyday-5683d.appspot.com IS_ADS_ENABLED - + IS_ANALYTICS_ENABLED - + IS_APPINVITE_ENABLED - + IS_GCM_ENABLED - + IS_SIGNIN_ENABLED - + GOOGLE_APP_ID 1:526363179403:ios:dd540ebe047c594dc4978e - \ No newline at end of file + diff --git a/Everyday/Support/SceneDelegate.swift b/Everyday/Support/SceneDelegate.swift index 36158d7..0a2d43f 100644 --- a/Everyday/Support/SceneDelegate.swift +++ b/Everyday/Support/SceneDelegate.swift @@ -12,14 +12,12 @@ import FirebaseAuth class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - private var splashPresenter: SplashPresenterDescription? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let scene = (scene as? UIWindowScene) else { - return + return } - splashPresenter = SplashPresenter(scene: scene) setupWindow(with: scene) if Auth.auth().currentUser == nil { @@ -30,15 +28,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window?.rootViewController = viewController } - splashPresenter?.present() - - let delay: TimeInterval = 1.5 - DispatchQueue.main.asyncAfter(deadline: .now() + delay) { - self.splashPresenter?.dismiss { [weak self] in - self?.splashPresenter = nil - } - } - checkAuthentication() } From 02f6faaf466e7280cceb6f7d2cfd53d75f39d0d5 Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Wed, 6 Mar 2024 15:07:44 +0300 Subject: [PATCH 10/13] results textfield fix --- Everyday/Extensions/String+Extension.swift | 6 ++++++ .../ResultsScene/ResultsTableViewCell.swift | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Everyday/Extensions/String+Extension.swift b/Everyday/Extensions/String+Extension.swift index 1c1e27d..4ed659b 100644 --- a/Everyday/Extensions/String+Extension.swift +++ b/Everyday/Extensions/String+Extension.swift @@ -11,4 +11,10 @@ extension String { var localized: String { NSLocalizedString(self, comment: "\(self) could not be found in Localized file") } + + var isNumber: Bool { + return self.allSatisfy { character in + character.isNumber + } + } } diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift index fc5a258..b9a3a1e 100644 --- a/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsTableViewCell.swift @@ -107,6 +107,8 @@ private extension ResultsTableViewCell { resultTextField.backgroundColor = .clear resultTextField.textColor = Constants.ResultTextField.textColor resultTextField.textAlignment = .center + resultTextField.keyboardType = .numberPad + resultTextField.addTarget(self, action: #selector(didEndEditingTextField), for: .editingDidEnd) } // MARK: - Actions @@ -115,7 +117,8 @@ private extension ResultsTableViewCell { func didTapMinusButton() { guard let resultText = resultTextField.text, - let result = Int(resultText) + let result = Int(resultText), + result > 0 else { return } @@ -134,6 +137,17 @@ private extension ResultsTableViewCell { resultTextField.text = String(result + 1) } + + @objc + func didEndEditingTextField() { + guard let resultText = resultTextField.text else { + return + } + + if resultText.isEmpty || !resultText.isNumber || Int(resultText) ?? 0 < 0 { + resultTextField.text = "0" + } + } } // MARK: - Constants From d75232a885f0edaddd82c0ec250798f2db705f7e Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Wed, 6 Mar 2024 16:32:46 +0300 Subject: [PATCH 11/13] multithreading fix --- .../Notepad/NotepadScene/NotepadViewController.swift | 12 ++---------- .../Notepad/ResultsScene/ResultsViewController.swift | 10 ++-------- .../TrainingScene/TrainingViewController.swift | 10 ++-------- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift b/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift index 5f115e2..6b47c4a 100644 --- a/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift +++ b/Everyday/Modules/Notepad/NotepadScene/NotepadViewController.swift @@ -182,13 +182,7 @@ extension NotepadViewController: NotepadViewInput { } func reloadData() { - DispatchQueue.main.async { [weak self] in - guard let self else { - return - } - - self.tableView.reloadData() - } + tableView.reloadData() } func showLoadingView() { @@ -202,9 +196,7 @@ extension NotepadViewController: NotepadViewInput { } func dismissLoadingView() { - DispatchQueue.main.async { - self.activityIndicator.removeFromSuperview() - } + activityIndicator.removeFromSuperview() } } diff --git a/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift b/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift index 32074ec..de76043 100644 --- a/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift +++ b/Everyday/Modules/Notepad/ResultsScene/ResultsViewController.swift @@ -220,14 +220,8 @@ extension ResultsViewController: ResultsViewInput { closeButton.setImage(viewModel.closeImage, for: .normal) } - func reloadData() { - DispatchQueue.main.async { [weak self] in - guard let self else { - return - } - - self.tableView.reloadData() - } + func reloadData() { + tableView.reloadData() } } diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift index 39b293f..ee43136 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingViewController.swift @@ -167,14 +167,8 @@ extension TrainingViewController: TrainingViewInput { finishButton.isHidden = true } - func reloadData() { - DispatchQueue.main.async { [weak self] in - guard let self else { - return - } - - self.tableView.reloadData() - } + func reloadData() { + tableView.reloadData() } } From 791845e09dc63130194f9d3d08ee9e5b9e299c46 Mon Sep 17 00:00:00 2001 From: fix1in1it Date: Thu, 7 Mar 2024 21:48:16 +0300 Subject: [PATCH 12/13] exercise routing hotfix --- .../Notepad/ExerciseScene/ExerciseRouter.swift | 7 ++----- .../Notepad/TrainingScene/TrainingRouter.swift | 13 ++++++------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Everyday/Modules/Notepad/ExerciseScene/ExerciseRouter.swift b/Everyday/Modules/Notepad/ExerciseScene/ExerciseRouter.swift index 0e4b891..57c4c7b 100644 --- a/Everyday/Modules/Notepad/ExerciseScene/ExerciseRouter.swift +++ b/Everyday/Modules/Notepad/ExerciseScene/ExerciseRouter.swift @@ -14,13 +14,10 @@ final class ExerciseRouter { extension ExerciseRouter: ExerciseRouterInput { func closeExercise() { - guard - let viewController = viewController, - let navigationController = viewController.navigationController - else { + guard let viewController = viewController else { return } - navigationController.popViewController(animated: true) + viewController.dismiss(animated: true) } } diff --git a/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift b/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift index 62ada35..ee384bf 100644 --- a/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift +++ b/Everyday/Modules/Notepad/TrainingScene/TrainingRouter.swift @@ -14,14 +14,13 @@ final class TrainingRouter { extension TrainingRouter: TrainingRouterInput { func openExercise(with exerciseContext: ExerciseContext) { - if let windowScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene, - let window = windowScene.windows.first(where: { $0.isKeyWindow }) { - let viewController = ExerciseContainer.assemble(with: exerciseContext).viewController - viewController.modalPresentationStyle = .fullScreen - UIView.transition(with: window, duration: 0.5, options: [.transitionCrossDissolve], animations: { - window.rootViewController = viewController - }, completion: nil) + guard let viewController = viewController else { + return } + + let exerciseContainer = ExerciseContainer.assemble(with: exerciseContext) + let exerciseViewController = exerciseContainer.viewController + viewController.present(exerciseViewController, animated: true) } func showResults(with resultsContext: ResultsContext) { From 8ef1cdf065cd8243904a786e10dbf6f695738f4a Mon Sep 17 00:00:00 2001 From: MX126 Date: Mon, 11 Mar 2024 15:05:07 +0300 Subject: [PATCH 13/13] added locales --- .../UserInterfaceState.xcuserstate | Bin 190485 -> 236988 bytes .../xcschemes/xcschememanagement.plist | 2 +- .../Models/ExerciseViewModel.swift | 4 +- .../Models/NotepadViewModel.swift | 4 +- .../Models/ResultsViewModel.swift | 12 +- .../TimerScene/Models/TimerViewModel.swift | 16 +- .../TrainingTableViewCellViewModel.swift | 4 +- .../Models/TrainingViewModel.swift | 4 +- Everyday/Support/Localizable.xcstrings | 187 ++++++++++++++++++ 9 files changed, 210 insertions(+), 23 deletions(-) diff --git a/Everyday.xcodeproj/project.xcworkspace/xcuserdata/mk126.xcuserdatad/UserInterfaceState.xcuserstate b/Everyday.xcodeproj/project.xcworkspace/xcuserdata/mk126.xcuserdatad/UserInterfaceState.xcuserstate index 54a27213b440aeb21a0b06046106ca3249516c5a..26fb60a372f7879b3c6c002e98f7c513572b2433 100644 GIT binary patch literal 236988 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

$NEo5xr%q{M6pGQ39 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 z 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 diff --git a/Everyday.xcodeproj/xcuserdata/mk126.xcuserdatad/xcschemes/xcschememanagement.plist b/Everyday.xcodeproj/xcuserdata/mk126.xcuserdatad/xcschemes/xcschememanagement.plist index dea58b3..f2cc571 100644 --- a/Everyday.xcodeproj/xcuserdata/mk126.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Everyday.xcodeproj/xcuserdata/mk126.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ Everyday.xcscheme_^#shared#^_ orderHint - 0 + 2 Playground (Playground) 1.xcscheme diff --git a/Everyday/Modules/Notepad/ExerciseScene/Models/ExerciseViewModel.swift b/Everyday/Modules/Notepad/ExerciseScene/Models/ExerciseViewModel.swift index b307981..2693c16 100644 --- a/Everyday/Modules/Notepad/ExerciseScene/Models/ExerciseViewModel.swift +++ b/Everyday/Modules/Notepad/ExerciseScene/Models/ExerciseViewModel.swift @@ -15,8 +15,8 @@ struct ExerciseViewModel { init(exercise: Exercise) { let resultLabelTitle = "0" let resultLabelAttributedString = NSAttributedString(string: resultLabelTitle, attributes: Styles.titleAttributes) - let saveButtonTitle = "Сохранить" - let saveButtonAttributedString = NSAttributedString(string: saveButtonTitle, attributes: Styles.titleAttributes) + let saveButtonTitle = "Exercise_save_title" + let saveButtonAttributedString = NSAttributedString(string: saveButtonTitle.localized, attributes: Styles.titleAttributes) self.title = exercise.name self.resultTitle = resultLabelAttributedString diff --git a/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift index b7a883e..8e34cb4 100644 --- a/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift +++ b/Everyday/Modules/Notepad/NotepadScene/Models/NotepadViewModel.swift @@ -11,8 +11,8 @@ struct NotepadViewModel { let stateTitle: NSAttributedString init(isResult: Bool) { - let stateLabelTitle = isResult ? "Результат" : "Ваш план" - let stateLabelAttributedString = NSAttributedString(string: stateLabelTitle, attributes: Styles.titleAttributes) + let stateLabelTitle = isResult ? "Journal_Results_Title" : "Journal_Plan_Title" + let stateLabelAttributedString = NSAttributedString(string: stateLabelTitle.localized, attributes: Styles.titleAttributes) self.stateTitle = stateLabelAttributedString } diff --git a/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift b/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift index 28a5e81..6b014ce 100644 --- a/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift +++ b/Everyday/Modules/Notepad/ResultsScene/Models/ResultsViewModel.swift @@ -14,12 +14,12 @@ struct ResultsViewModel { let closeImage: UIImage? init() { - let resultsLabelTitle = "Результаты" - let resultsLabelAttributedString = NSAttributedString(string: resultsLabelTitle, attributes: Styles.titleAttributes) - let restButtonTitle = "Отдых" - let restButtonAttributedString = NSAttributedString(string: restButtonTitle, attributes: Styles.buttonTitleAttributes) - let continueButtonTitle = "Продолжить" - let continueButtonAttributedString = NSAttributedString(string: continueButtonTitle, attributes: Styles.buttonTitleAttributes) + let resultsLabelTitle = "Progress_title" + let resultsLabelAttributedString = NSAttributedString(string: resultsLabelTitle.localized, attributes: Styles.titleAttributes) + let restButtonTitle = "Results_Rest_Button_Title" + let restButtonAttributedString = NSAttributedString(string: restButtonTitle.localized, attributes: Styles.buttonTitleAttributes) + let continueButtonTitle = "Results_Continue_Button_Title" + let continueButtonAttributedString = NSAttributedString(string: continueButtonTitle.localized, attributes: Styles.buttonTitleAttributes) let closeButtonImageName = "xmark.circle.fill" let closeButtonImage = UIImage(systemName: closeButtonImageName, withConfiguration: Configurations.large) diff --git a/Everyday/Modules/Notepad/TimerScene/Models/TimerViewModel.swift b/Everyday/Modules/Notepad/TimerScene/Models/TimerViewModel.swift index e4f6518..0e83229 100644 --- a/Everyday/Modules/Notepad/TimerScene/Models/TimerViewModel.swift +++ b/Everyday/Modules/Notepad/TimerScene/Models/TimerViewModel.swift @@ -17,14 +17,14 @@ struct TimerViewModel { init(remainingTime: Int) { let remainingTimeLabelTitle = "\(remainingTime)" let remainingTimeLabelAttributedString = NSAttributedString(string: remainingTimeLabelTitle, attributes: Styles.titleAttributes) - let startButtonTitle = "Старт" - let startButtonAttributedString = NSAttributedString(string: startButtonTitle, attributes: Styles.titleAttributes) - let stopButtonTitle = "Стоп" - let stopButtonAttributedString = NSAttributedString(string: stopButtonTitle, attributes: Styles.titleAttributes) - let resetButtonTitle = "Заново" - let resetButtonAttributedString = NSAttributedString(string: resetButtonTitle, attributes: Styles.titleAttributes) - let skipButtonTitle = "Пропустить" - let skipButtonAttributedString = NSAttributedString(string: skipButtonTitle, attributes: Styles.titleAttributes) + let startButtonTitle = "Timer_Start_Button_Title" + let startButtonAttributedString = NSAttributedString(string: startButtonTitle.localized, attributes: Styles.titleAttributes) + let stopButtonTitle = "Timer_Stop_Button_Title" + let stopButtonAttributedString = NSAttributedString(string: stopButtonTitle.localized, attributes: Styles.titleAttributes) + let resetButtonTitle = "Timer_Restart_Button_Title" + let resetButtonAttributedString = NSAttributedString(string: resetButtonTitle.localized, attributes: Styles.titleAttributes) + let skipButtonTitle = "Timer_Skip_Button_Title" + let skipButtonAttributedString = NSAttributedString(string: skipButtonTitle.localized, attributes: Styles.titleAttributes) self.remainingTimeTitle = remainingTimeLabelAttributedString self.startTitle = startButtonAttributedString diff --git a/Everyday/Modules/Notepad/TrainingScene/Models/TrainingTableViewCellViewModel.swift b/Everyday/Modules/Notepad/TrainingScene/Models/TrainingTableViewCellViewModel.swift index 79092ec..402f73c 100644 --- a/Everyday/Modules/Notepad/TrainingScene/Models/TrainingTableViewCellViewModel.swift +++ b/Everyday/Modules/Notepad/TrainingScene/Models/TrainingTableViewCellViewModel.swift @@ -17,8 +17,8 @@ struct TrainingTableViewCellViewModel { let titleLabelAttributedString = NSAttributedString(string: titleLabelTitle, attributes: Styles.titleAttributes) let resultLabelTitle = exercise.result let resultLabelAttributedString = NSAttributedString(string: resultLabelTitle, attributes: Styles.resultAttributes) - let startButtonTitle = "Начать" - let startButtonAttributedString = NSAttributedString(string: startButtonTitle, attributes: Styles.titleAttributes) + let startButtonTitle = "Timer_Start_Button_Title" + let startButtonAttributedString = NSAttributedString(string: startButtonTitle.localized, attributes: Styles.titleAttributes) self.title = titleLabelAttributedString self.result = resultLabelAttributedString diff --git a/Everyday/Modules/Notepad/TrainingScene/Models/TrainingViewModel.swift b/Everyday/Modules/Notepad/TrainingScene/Models/TrainingViewModel.swift index ae8c88b..967a65a 100644 --- a/Everyday/Modules/Notepad/TrainingScene/Models/TrainingViewModel.swift +++ b/Everyday/Modules/Notepad/TrainingScene/Models/TrainingViewModel.swift @@ -11,8 +11,8 @@ struct TrainingViewModel { let finishTitle: NSAttributedString init() { - let finishButtonTitle = "Закончить" - let finishButtonAttributedString = NSAttributedString(string: finishButtonTitle, attributes: Styles.titleAttributes) + let finishButtonTitle = "Training_Finish_Button_Title" + let finishButtonAttributedString = NSAttributedString(string: finishButtonTitle.localized, attributes: Styles.titleAttributes) self.finishTitle = finishButtonAttributedString } diff --git a/Everyday/Support/Localizable.xcstrings b/Everyday/Support/Localizable.xcstrings index 876c115..5cb5df5 100644 --- a/Everyday/Support/Localizable.xcstrings +++ b/Everyday/Support/Localizable.xcstrings @@ -222,6 +222,74 @@ } } }, + "Back_Button_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Back" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Назад" + } + } + } + }, + "Exercise_save_title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сохранить" + } + } + } + }, + "Journal_Plan_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your plan" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ваш план" + } + } + } + }, + "Journal_Results_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Results" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Результаты" + } + } + } + }, "keyboard_toolbar_ready_title" : { "extractionState" : "manual", "localizations" : { @@ -1055,6 +1123,40 @@ } } }, + "Results_Continue_Button_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Continue" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Продолжить" + } + } + } + }, + "Results_Rest_Button_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rest" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Отдых" + } + } + } + }, "Settings_title" : { "extractionState" : "manual", "localizations" : { @@ -1191,6 +1293,91 @@ } } }, + "Timer_Restart_Button_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Restart" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Заново" + } + } + } + }, + "Timer_Skip_Button_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Skip" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пропустить" + } + } + } + }, + "Timer_Start_Button_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Start" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Начать" + } + } + } + }, + "Timer_Stop_Button_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stop" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стоп" + } + } + } + }, + "Training_Finish_Button_Title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Finish" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Завершить" + } + } + } + }, "Validator_digit" : { "extractionState" : "manual", "localizations" : {