git.iko.soy/dashared/hookah-tau
on develop help sign in
Merge pull request #18 from dashared/reservations/api-and-models
1445be5Darya Rednikina
Hookah Tau.xcodeproj/project.pbxproj+272−4
@@ -7,9 +7,24 @@
7 objects = {
7 objects = {
8
8
9/* Begin PBXBuildFile section */
9/* Begin PBXBuildFile section */
10+ 12050569238048CE00801618 /* Extensions+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12050568238048CE00801618 /* Extensions+Date.swift */; };
11+ 1205056B2380588C00801618 /* Extenstions+IBDesignable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1205056A2380588C00801618 /* Extenstions+IBDesignable.swift */; };
12+ 120BFC7723891925001EBE89 /* ThirdStepReservationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120BFC7623891925001EBE89 /* ThirdStepReservationViewController.swift */; };
13+ 120BFC7923891942001EBE89 /* ThirdStepReservationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120BFC7823891942001EBE89 /* ThirdStepReservationCoordinator.swift */; };
14+ 120BFC7C23891965001EBE89 /* ThirdStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 120BFC7B23891965001EBE89 /* ThirdStepView.swift */; };
15+ 120BFC7E23891975001EBE89 /* ThirdStepView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 120BFC7D23891975001EBE89 /* ThirdStepView.xib */; };
10 12118B9C23682022006BAEE3 /* RegistrationResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12118B9B23682022006BAEE3 /* RegistrationResolver.swift */; };
16 12118B9C23682022006BAEE3 /* RegistrationResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12118B9B23682022006BAEE3 /* RegistrationResolver.swift */; };
11 12118B9E23682049006BAEE3 /* PhoneCodeResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12118B9D23682049006BAEE3 /* PhoneCodeResolver.swift */; };
17 12118B9E23682049006BAEE3 /* PhoneCodeResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12118B9D23682049006BAEE3 /* PhoneCodeResolver.swift */; };
18+ 1212048C23914CFD00CAF162 /* DeleteReservationResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1212048B23914CFD00CAF162 /* DeleteReservationResolver.swift */; };
19+ 1212048E23915A0A00CAF162 /* ChangeReservationResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1212048D23915A0A00CAF162 /* ChangeReservationResolver.swift */; };
12 12219CEF2353A63F0057DDEE /* ReservationsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12219CEE2353A63E0057DDEE /* ReservationsCoordinator.swift */; };
20 12219CEF2353A63F0057DDEE /* ReservationsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12219CEE2353A63E0057DDEE /* ReservationsCoordinator.swift */; };
21+ 12230AEA238FD8B3004A01E5 /* MapView2.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12230AE9238FD8B3004A01E5 /* MapView2.xib */; };
22+ 12230AEC238FD8C5004A01E5 /* MapView2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12230AEB238FD8C5004A01E5 /* MapView2.swift */; };
23+ 12230AF123900974004A01E5 /* TotalStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12230AF023900974004A01E5 /* TotalStorage.swift */; };
24+ 12230AF423900BCB004A01E5 /* EstablishmentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12230AF323900BCB004A01E5 /* EstablishmentService.swift */; };
25+ 12230AF723900D44004A01E5 /* EstablishmentResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12230AF623900D44004A01E5 /* EstablishmentResolver.swift */; };
26+ 12230AFA23901029004A01E5 /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12230AF923901029004A01E5 /* DataStorage.swift */; };
27+ 12230AFC239034D3004A01E5 /* SecondStepReservationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12230AFB239034D3004A01E5 /* SecondStepReservationViewController.swift */; };
13 123615CF235510BC00D1122A /* ProfileView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 123615CE235510BC00D1122A /* ProfileView.xib */; };
28 123615CF235510BC00D1122A /* ProfileView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 123615CE235510BC00D1122A /* ProfileView.xib */; };
14 123615D12355141600D1122A /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123615D02355141600D1122A /* ProfileView.swift */; };
29 123615D12355141600D1122A /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123615D02355141600D1122A /* ProfileView.swift */; };
15 12387337234BB98700D1F1AB /* CodeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12387336234BB98700D1F1AB /* CodeView.xib */; };
30 12387337234BB98700D1F1AB /* CodeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12387336234BB98700D1F1AB /* CodeView.xib */; };
@@ -18,6 +33,12 @@
18 1246B71C235CDF3A004CBFA1 /* ReservationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1246B71B235CDF3A004CBFA1 /* ReservationCell.swift */; };
33 1246B71C235CDF3A004CBFA1 /* ReservationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1246B71B235CDF3A004CBFA1 /* ReservationCell.swift */; };
19 1246B71E235CDF8A004CBFA1 /* ReservationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1246B71D235CDF8A004CBFA1 /* ReservationView.xib */; };
34 1246B71E235CDF8A004CBFA1 /* ReservationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1246B71D235CDF8A004CBFA1 /* ReservationView.xib */; };
20 1246B720235CDF9E004CBFA1 /* ReservationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1246B71F235CDF9E004CBFA1 /* ReservationView.swift */; };
35 1246B720235CDF9E004CBFA1 /* ReservationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1246B71F235CDF9E004CBFA1 /* ReservationView.swift */; };
36+ 124D007C23721FD400AE76B9 /* Reservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124D007B23721FD400AE76B9 /* Reservation.swift */; };
37+ 124D007F237222B200AE76B9 /* ReservationsResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124D007E237222B200AE76B9 /* ReservationsResolver.swift */; };
38+ 124D0081237222C900AE76B9 /* ReservationsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124D0080237222C900AE76B9 /* ReservationsService.swift */; };
39+ 125AE51D2395583E00F847BD /* ChangeReservationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125AE51C2395583E00F847BD /* ChangeReservationCoordinator.swift */; };
40+ 125AE51F2395585300F847BD /* ChangeReservationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125AE51E2395585300F847BD /* ChangeReservationViewController.swift */; };
41+ 125AE5212395753400F847BD /* HFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125AE5202395753400F847BD /* HFunc.swift */; };
21 12838EA9236764A600CEF108 /* APIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EA8236764A600CEF108 /* APIClient.swift */; };
42 12838EA9236764A600CEF108 /* APIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EA8236764A600CEF108 /* APIClient.swift */; };
22 12838EAC2367689600CEF108 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 12838EAB2367689600CEF108 /* Alamofire */; };
43 12838EAC2367689600CEF108 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 12838EAB2367689600CEF108 /* Alamofire */; };
23 12838EAE2367701300CEF108 /* AuthorizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EAD2367701300CEF108 /* AuthorizationService.swift */; };
44 12838EAE2367701300CEF108 /* AuthorizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EAD2367701300CEF108 /* AuthorizationService.swift */; };
@@ -26,14 +47,28 @@
26 12838EB4236779C700CEF108 /* ApiResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EB3236779C700CEF108 /* ApiResolver.swift */; };
47 12838EB4236779C700CEF108 /* ApiResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EB3236779C700CEF108 /* ApiResolver.swift */; };
27 12838EB623677FB900CEF108 /* ApiRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EB523677FB900CEF108 /* ApiRequest.swift */; };
48 12838EB623677FB900CEF108 /* ApiRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EB523677FB900CEF108 /* ApiRequest.swift */; };
28 12838EB82367834900CEF108 /* MyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EB72367834900CEF108 /* MyCodable.swift */; };
49 12838EB82367834900CEF108 /* MyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12838EB72367834900CEF108 /* MyCodable.swift */; };
50+ 12A075F72373535C00D749BB /* FirstStepReservationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A075F62373535C00D749BB /* FirstStepReservationViewController.swift */; };
51+ 12A075F9237353F500D749BB /* MapView1.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12A075F8237353F500D749BB /* MapView1.xib */; };
52+ 12A075FB2373561A00D749BB /* Reservation.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12A075FA2373561A00D749BB /* Reservation.storyboard */; };
53+ 12A075FD237357E900D749BB /* FirstStepReservationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A075FC237357E900D749BB /* FirstStepReservationCoordinator.swift */; };
54+ 12A075FF237358F200D749BB /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A075FE237358F200D749BB /* MapView.swift */; };
55+ 12A07601237359BB00D749BB /* MapView1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12A07600237359BB00D749BB /* MapView1.swift */; };
56+ 12B4447C238EF25C000B6B16 /* CreateReservationResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B4447B238EF25C000B6B16 /* CreateReservationResolver.swift */; };
29 12B6A60F235B857A00898B31 /* ProfileChangeCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6A60E235B857A00898B31 /* ProfileChangeCoordinator.swift */; };
57 12B6A60F235B857A00898B31 /* ProfileChangeCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6A60E235B857A00898B31 /* ProfileChangeCoordinator.swift */; };
30 12B6A611235B8EC500898B31 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6A610235B8EC500898B31 /* User.swift */; };
58 12B6A611235B8EC500898B31 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6A610235B8EC500898B31 /* User.swift */; };
31 12B6A613235B9B4300898B31 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6A612235B9B4300898B31 /* BaseViewController.swift */; };
59 12B6A613235B9B4300898B31 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6A612235B9B4300898B31 /* BaseViewController.swift */; };
32 12B6A615235BB36C00898B31 /* ChangeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12B6A614235BB36C00898B31 /* ChangeView.xib */; };
60 12B6A615235BB36C00898B31 /* ChangeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12B6A614235BB36C00898B31 /* ChangeView.xib */; };
33 12B6A617235BB37D00898B31 /* ChangeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6A616235BB37D00898B31 /* ChangeView.swift */; };
61 12B6A617235BB37D00898B31 /* ChangeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12B6A616235BB37D00898B31 /* ChangeView.swift */; };
62+ 12BD95B0237EBEDF009614D8 /* FirstStepView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12BD95AF237EBEDE009614D8 /* FirstStepView.xib */; };
63+ 12BD95B2237EC22B009614D8 /* FirstStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BD95B1237EC22B009614D8 /* FirstStepView.swift */; };
64+ 12BD95B6237ED8AC009614D8 /* TimePointView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12BD95B5237ED8AB009614D8 /* TimePointView.xib */; };
65+ 12BD95B8237EDB01009614D8 /* TimePointView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BD95B7237EDB01009614D8 /* TimePointView.swift */; };
34 12C72EDF23537D1B00AD7004 /* ProfileCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C72EDE23537D1B00AD7004 /* ProfileCoordinator.swift */; };
66 12C72EDF23537D1B00AD7004 /* ProfileCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C72EDE23537D1B00AD7004 /* ProfileCoordinator.swift */; };
35 12C72EE1235380D400AD7004 /* ProfileClientViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C72EE0235380D400AD7004 /* ProfileClientViewController.swift */; };
67 12C72EE1235380D400AD7004 /* ProfileClientViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C72EE0235380D400AD7004 /* ProfileClientViewController.swift */; };
36 12C72EE3235380EB00AD7004 /* ReservationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C72EE2235380EB00AD7004 /* ReservationsViewController.swift */; };
68 12C72EE3235380EB00AD7004 /* ReservationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C72EE2235380EB00AD7004 /* ReservationsViewController.swift */; };
69+ 12D8FA2D237F003800305F57 /* DateView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12D8FA2C237F003800305F57 /* DateView.xib */; };
70+ 12D8FA2F237F00E200305F57 /* DateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D8FA2E237F00E200305F57 /* DateView.swift */; };
71+ 12D8FA31237F08C700305F57 /* AllReservations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D8FA30237F08C700305F57 /* AllReservations.swift */; };
37 12DBEEB223539F2100AF1BB6 /* Client.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12DBEEB123539F2100AF1BB6 /* Client.storyboard */; };
72 12DBEEB223539F2100AF1BB6 /* Client.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12DBEEB123539F2100AF1BB6 /* Client.storyboard */; };
38 12EA99462362B674005D9FE9 /* AddressCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EA99452362B674005D9FE9 /* AddressCoordinator.swift */; };
73 12EA99462362B674005D9FE9 /* AddressCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EA99452362B674005D9FE9 /* AddressCoordinator.swift */; };
39 12EA99482362B684005D9FE9 /* AddresViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EA99472362B684005D9FE9 /* AddresViewController.swift */; };
74 12EA99482362B684005D9FE9 /* AddresViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EA99472362B684005D9FE9 /* AddresViewController.swift */; };
@@ -42,7 +77,11 @@
42 12EB698123661CB300E4D1CE /* AddressCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EB698023661CB300E4D1CE /* AddressCell.swift */; };
77 12EB698123661CB300E4D1CE /* AddressCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EB698023661CB300E4D1CE /* AddressCell.swift */; };
43 12EE4A76234BB8FE005B4D1A /* CodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EE4A75234BB8FE005B4D1A /* CodeView.swift */; };
78 12EE4A76234BB8FE005B4D1A /* CodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12EE4A75234BB8FE005B4D1A /* CodeView.swift */; };
44 12F73B022357AD7B007D4476 /* ProfileChangeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F73B012357AD7B007D4476 /* ProfileChangeViewController.swift */; };
79 12F73B022357AD7B007D4476 /* ProfileChangeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F73B012357AD7B007D4476 /* ProfileChangeViewController.swift */; };
45− 12FE4042236B8B050012391E /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FE4041236B8B050012391E /* DataStorage.swift */; };
80+ 12F9652A23868E6000FCA696 /* SecondStepView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 12F9652923868E6000FCA696 /* SecondStepView.xib */; };
81+ 12F9652C23868E7200FCA696 /* SecondStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F9652B23868E7200FCA696 /* SecondStepView.swift */; };
82+ 12F9652E23869F3100FCA696 /* SecondStepReservationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F9652D23869F3100FCA696 /* SecondStepReservationCoordinator.swift */; };
83+ 12FC40382382C93D00AB593B /* TableButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FC40372382C93C00AB593B /* TableButtonStyle.swift */; };
84+ 12FC403A2382CB6F00AB593B /* TableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FC40392382CB6F00AB593B /* TableButton.swift */; };
46 F30369B5233679EA00A8EA84 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F30369B4233679EA00A8EA84 /* LaunchScreen.storyboard */; };
85 F30369B5233679EA00A8EA84 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F30369B4233679EA00A8EA84 /* LaunchScreen.storyboard */; };
47 F30369BE2336924D00A8EA84 /* ClientTabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F30369BD2336924D00A8EA84 /* ClientTabbarCoordinator.swift */; };
86 F30369BE2336924D00A8EA84 /* ClientTabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F30369BD2336924D00A8EA84 /* ClientTabbarCoordinator.swift */; };
48 F30369C02336925800A8EA84 /* ClientTabbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F30369BF2336925800A8EA84 /* ClientTabbarController.swift */; };
87 F30369C02336925800A8EA84 /* ClientTabbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F30369BF2336925800A8EA84 /* ClientTabbarController.swift */; };
@@ -91,9 +130,24 @@
91/* End PBXContainerItemProxy section */
130/* End PBXContainerItemProxy section */
92
131
93/* Begin PBXFileReference section */
132/* Begin PBXFileReference section */
133+ 12050568238048CE00801618 /* Extensions+Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extensions+Date.swift"; sourceTree = "<group>"; };
134+ 1205056A2380588C00801618 /* Extenstions+IBDesignable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extenstions+IBDesignable.swift"; sourceTree = "<group>"; };
135+ 120BFC7623891925001EBE89 /* ThirdStepReservationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdStepReservationViewController.swift; sourceTree = "<group>"; };
136+ 120BFC7823891942001EBE89 /* ThirdStepReservationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdStepReservationCoordinator.swift; sourceTree = "<group>"; };
137+ 120BFC7B23891965001EBE89 /* ThirdStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdStepView.swift; sourceTree = "<group>"; };
138+ 120BFC7D23891975001EBE89 /* ThirdStepView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ThirdStepView.xib; sourceTree = "<group>"; };
94 12118B9B23682022006BAEE3 /* RegistrationResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationResolver.swift; sourceTree = "<group>"; };
139 12118B9B23682022006BAEE3 /* RegistrationResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationResolver.swift; sourceTree = "<group>"; };
95 12118B9D23682049006BAEE3 /* PhoneCodeResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneCodeResolver.swift; sourceTree = "<group>"; };
140 12118B9D23682049006BAEE3 /* PhoneCodeResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneCodeResolver.swift; sourceTree = "<group>"; };
141+ 1212048B23914CFD00CAF162 /* DeleteReservationResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteReservationResolver.swift; sourceTree = "<group>"; };
142+ 1212048D23915A0A00CAF162 /* ChangeReservationResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeReservationResolver.swift; sourceTree = "<group>"; };
96 12219CEE2353A63E0057DDEE /* ReservationsCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReservationsCoordinator.swift; sourceTree = "<group>"; };
143 12219CEE2353A63E0057DDEE /* ReservationsCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReservationsCoordinator.swift; sourceTree = "<group>"; };
144+ 12230AE9238FD8B3004A01E5 /* MapView2.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MapView2.xib; sourceTree = "<group>"; };
145+ 12230AEB238FD8C5004A01E5 /* MapView2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView2.swift; sourceTree = "<group>"; };
146+ 12230AF023900974004A01E5 /* TotalStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalStorage.swift; sourceTree = "<group>"; };
147+ 12230AF323900BCB004A01E5 /* EstablishmentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EstablishmentService.swift; sourceTree = "<group>"; };
148+ 12230AF623900D44004A01E5 /* EstablishmentResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EstablishmentResolver.swift; sourceTree = "<group>"; };
149+ 12230AF923901029004A01E5 /* DataStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataStorage.swift; sourceTree = "<group>"; };
150+ 12230AFB239034D3004A01E5 /* SecondStepReservationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondStepReservationViewController.swift; sourceTree = "<group>"; };
97 123615CE235510BC00D1122A /* ProfileView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ProfileView.xib; sourceTree = "<group>"; };
151 123615CE235510BC00D1122A /* ProfileView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ProfileView.xib; sourceTree = "<group>"; };
98 123615D02355141600D1122A /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
152 123615D02355141600D1122A /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
99 12387336234BB98700D1F1AB /* CodeView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CodeView.xib; sourceTree = "<group>"; };
153 12387336234BB98700D1F1AB /* CodeView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CodeView.xib; sourceTree = "<group>"; };
@@ -102,6 +156,12 @@
102 1246B71B235CDF3A004CBFA1 /* ReservationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservationCell.swift; sourceTree = "<group>"; };
156 1246B71B235CDF3A004CBFA1 /* ReservationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservationCell.swift; sourceTree = "<group>"; };
103 1246B71D235CDF8A004CBFA1 /* ReservationView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReservationView.xib; sourceTree = "<group>"; };
157 1246B71D235CDF8A004CBFA1 /* ReservationView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReservationView.xib; sourceTree = "<group>"; };
104 1246B71F235CDF9E004CBFA1 /* ReservationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservationView.swift; sourceTree = "<group>"; };
158 1246B71F235CDF9E004CBFA1 /* ReservationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservationView.swift; sourceTree = "<group>"; };
159+ 124D007B23721FD400AE76B9 /* Reservation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Reservation.swift; sourceTree = "<group>"; };
160+ 124D007E237222B200AE76B9 /* ReservationsResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservationsResolver.swift; sourceTree = "<group>"; };
161+ 124D0080237222C900AE76B9 /* ReservationsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservationsService.swift; sourceTree = "<group>"; };
162+ 125AE51C2395583E00F847BD /* ChangeReservationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeReservationCoordinator.swift; sourceTree = "<group>"; };
163+ 125AE51E2395585300F847BD /* ChangeReservationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeReservationViewController.swift; sourceTree = "<group>"; };
164+ 125AE5202395753400F847BD /* HFunc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HFunc.swift; sourceTree = "<group>"; };
105 12838EA8236764A600CEF108 /* APIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIClient.swift; sourceTree = "<group>"; };
165 12838EA8236764A600CEF108 /* APIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIClient.swift; sourceTree = "<group>"; };
106 12838EAD2367701300CEF108 /* AuthorizationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationService.swift; sourceTree = "<group>"; };
166 12838EAD2367701300CEF108 /* AuthorizationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationService.swift; sourceTree = "<group>"; };
107 12838EAF236777D400CEF108 /* ServerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerError.swift; sourceTree = "<group>"; };
167 12838EAF236777D400CEF108 /* ServerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerError.swift; sourceTree = "<group>"; };
@@ -109,14 +169,28 @@
109 12838EB3236779C700CEF108 /* ApiResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiResolver.swift; sourceTree = "<group>"; };
169 12838EB3236779C700CEF108 /* ApiResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiResolver.swift; sourceTree = "<group>"; };
110 12838EB523677FB900CEF108 /* ApiRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiRequest.swift; sourceTree = "<group>"; };
170 12838EB523677FB900CEF108 /* ApiRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiRequest.swift; sourceTree = "<group>"; };
111 12838EB72367834900CEF108 /* MyCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCodable.swift; sourceTree = "<group>"; };
171 12838EB72367834900CEF108 /* MyCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyCodable.swift; sourceTree = "<group>"; };
172+ 12A075F62373535C00D749BB /* FirstStepReservationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstStepReservationViewController.swift; sourceTree = "<group>"; };
173+ 12A075F8237353F500D749BB /* MapView1.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MapView1.xib; sourceTree = "<group>"; };
174+ 12A075FA2373561A00D749BB /* Reservation.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Reservation.storyboard; sourceTree = "<group>"; };
175+ 12A075FC237357E900D749BB /* FirstStepReservationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstStepReservationCoordinator.swift; sourceTree = "<group>"; };
176+ 12A075FE237358F200D749BB /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = "<group>"; };
177+ 12A07600237359BB00D749BB /* MapView1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView1.swift; sourceTree = "<group>"; };
178+ 12B4447B238EF25C000B6B16 /* CreateReservationResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateReservationResolver.swift; sourceTree = "<group>"; };
112 12B6A60E235B857A00898B31 /* ProfileChangeCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileChangeCoordinator.swift; sourceTree = "<group>"; };
179 12B6A60E235B857A00898B31 /* ProfileChangeCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileChangeCoordinator.swift; sourceTree = "<group>"; };
113 12B6A610235B8EC500898B31 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
180 12B6A610235B8EC500898B31 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
114 12B6A612235B9B4300898B31 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = "<group>"; };
181 12B6A612235B9B4300898B31 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = "<group>"; };
115 12B6A614235BB36C00898B31 /* ChangeView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ChangeView.xib; sourceTree = "<group>"; };
182 12B6A614235BB36C00898B31 /* ChangeView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ChangeView.xib; sourceTree = "<group>"; };
116 12B6A616235BB37D00898B31 /* ChangeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeView.swift; sourceTree = "<group>"; };
183 12B6A616235BB37D00898B31 /* ChangeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeView.swift; sourceTree = "<group>"; };
184+ 12BD95AF237EBEDE009614D8 /* FirstStepView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FirstStepView.xib; sourceTree = "<group>"; };
185+ 12BD95B1237EC22B009614D8 /* FirstStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstStepView.swift; sourceTree = "<group>"; };
186+ 12BD95B5237ED8AB009614D8 /* TimePointView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TimePointView.xib; sourceTree = "<group>"; };
187+ 12BD95B7237EDB01009614D8 /* TimePointView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimePointView.swift; sourceTree = "<group>"; };
117 12C72EDE23537D1B00AD7004 /* ProfileCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileCoordinator.swift; sourceTree = "<group>"; };
188 12C72EDE23537D1B00AD7004 /* ProfileCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileCoordinator.swift; sourceTree = "<group>"; };
118 12C72EE0235380D400AD7004 /* ProfileClientViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileClientViewController.swift; sourceTree = "<group>"; };
189 12C72EE0235380D400AD7004 /* ProfileClientViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileClientViewController.swift; sourceTree = "<group>"; };
119 12C72EE2235380EB00AD7004 /* ReservationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservationsViewController.swift; sourceTree = "<group>"; };
190 12C72EE2235380EB00AD7004 /* ReservationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservationsViewController.swift; sourceTree = "<group>"; };
191+ 12D8FA2C237F003800305F57 /* DateView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DateView.xib; sourceTree = "<group>"; };
192+ 12D8FA2E237F00E200305F57 /* DateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateView.swift; sourceTree = "<group>"; };
193+ 12D8FA30237F08C700305F57 /* AllReservations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllReservations.swift; sourceTree = "<group>"; };
120 12DBEEB123539F2100AF1BB6 /* Client.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Client.storyboard; sourceTree = "<group>"; };
194 12DBEEB123539F2100AF1BB6 /* Client.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Client.storyboard; sourceTree = "<group>"; };
121 12EA99452362B674005D9FE9 /* AddressCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCoordinator.swift; sourceTree = "<group>"; };
195 12EA99452362B674005D9FE9 /* AddressCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCoordinator.swift; sourceTree = "<group>"; };
122 12EA99472362B684005D9FE9 /* AddresViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddresViewController.swift; sourceTree = "<group>"; };
196 12EA99472362B684005D9FE9 /* AddresViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddresViewController.swift; sourceTree = "<group>"; };
@@ -125,7 +199,11 @@
125 12EB698023661CB300E4D1CE /* AddressCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCell.swift; sourceTree = "<group>"; };
199 12EB698023661CB300E4D1CE /* AddressCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressCell.swift; sourceTree = "<group>"; };
126 12EE4A75234BB8FE005B4D1A /* CodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeView.swift; sourceTree = "<group>"; };
200 12EE4A75234BB8FE005B4D1A /* CodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeView.swift; sourceTree = "<group>"; };
127 12F73B012357AD7B007D4476 /* ProfileChangeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileChangeViewController.swift; sourceTree = "<group>"; };
201 12F73B012357AD7B007D4476 /* ProfileChangeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileChangeViewController.swift; sourceTree = "<group>"; };
202+ 12F9652923868E6000FCA696 /* SecondStepView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SecondStepView.xib; sourceTree = "<group>"; };
203+ 12F9652B23868E7200FCA696 /* SecondStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondStepView.swift; sourceTree = "<group>"; };
204+ 12F9652D23869F3100FCA696 /* SecondStepReservationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondStepReservationCoordinator.swift; sourceTree = "<group>"; };
205+ 12FC40372382C93C00AB593B /* TableButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableButtonStyle.swift; sourceTree = "<group>"; };
128− 12FE4041236B8B050012391E /* DataStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStorage.swift; sourceTree = SOURCE_ROOT; };
206+ 12FC40392382CB6F00AB593B /* TableButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableButton.swift; sourceTree = "<group>"; };
129 F30369B4233679EA00A8EA84 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
207 F30369B4233679EA00A8EA84 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
130 F30369BD2336924D00A8EA84 /* ClientTabbarCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientTabbarCoordinator.swift; sourceTree = "<group>"; };
208 F30369BD2336924D00A8EA84 /* ClientTabbarCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientTabbarCoordinator.swift; sourceTree = "<group>"; };
131 F30369BF2336925800A8EA84 /* ClientTabbarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientTabbarController.swift; sourceTree = "<group>"; };
209 F30369BF2336925800A8EA84 /* ClientTabbarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientTabbarController.swift; sourceTree = "<group>"; };
@@ -188,6 +266,17 @@
188/* End PBXFrameworksBuildPhase section */
266/* End PBXFrameworksBuildPhase section */
189
267
190/* Begin PBXGroup section */
268/* Begin PBXGroup section */
269+ 120BFC7A2389194B001EBE89 /* 3 */ = {
270+ isa = PBXGroup;
271+ children = (
272+ 120BFC7623891925001EBE89 /* ThirdStepReservationViewController.swift */,
273+ 120BFC7823891942001EBE89 /* ThirdStepReservationCoordinator.swift */,
274+ 120BFC7B23891965001EBE89 /* ThirdStepView.swift */,
275+ 120BFC7D23891975001EBE89 /* ThirdStepView.xib */,
276+ );
277+ path = 3;
278+ sourceTree = "<group>";
279+ };
191 12118B9A2368187B006BAEE3 /* Authorization api */ = {
280 12118B9A2368187B006BAEE3 /* Authorization api */ = {
192 isa = PBXGroup;
281 isa = PBXGroup;
193 children = (
282 children = (
@@ -222,6 +311,9 @@
222 1212F1322353A603005BEF8A /* Reservations */ = {
311 1212F1322353A603005BEF8A /* Reservations */ = {
223 isa = PBXGroup;
312 isa = PBXGroup;
224 children = (
313 children = (
314+ 12BD95AE237EBE52009614D8 /* Maps */,
315+ 12BD95B3237EC231009614D8 /* Steps */,
316+ 12A075FA2373561A00D749BB /* Reservation.storyboard */,
225 1246B721235CDFC2004CBFA1 /* Cells */,
317 1246B721235CDFC2004CBFA1 /* Cells */,
226 1246B71A235CD4C5004CBFA1 /* Views */,
318 1246B71A235CD4C5004CBFA1 /* Views */,
227 12EA994A2362BA11005D9FE9 /* Active Reservations */,
319 12EA994A2362BA11005D9FE9 /* Active Reservations */,
@@ -230,6 +322,61 @@
230 path = Reservations;
322 path = Reservations;
231 sourceTree = "<group>";
323 sourceTree = "<group>";
232 };
324 };
325+ 12230AED238FD8D5004A01E5 /* 1 */ = {
326+ isa = PBXGroup;
327+ children = (
328+ 12A075F8237353F500D749BB /* MapView1.xib */,
329+ 12A07600237359BB00D749BB /* MapView1.swift */,
330+ );
331+ path = 1;
332+ sourceTree = "<group>";
333+ };
334+ 12230AEE238FD8DE004A01E5 /* 2 */ = {
335+ isa = PBXGroup;
336+ children = (
337+ 12230AE9238FD8B3004A01E5 /* MapView2.xib */,
338+ 12230AEB238FD8C5004A01E5 /* MapView2.swift */,
339+ );
340+ path = 2;
341+ sourceTree = "<group>";
342+ };
343+ 12230AEF239008F8004A01E5 /* Common */ = {
344+ isa = PBXGroup;
345+ children = (
346+ 12BD95B7237EDB01009614D8 /* TimePointView.swift */,
347+ 12BD95B5237ED8AB009614D8 /* TimePointView.xib */,
348+ 12D8FA2E237F00E200305F57 /* DateView.swift */,
349+ 12D8FA2C237F003800305F57 /* DateView.xib */,
350+ );
351+ path = Common;
352+ sourceTree = "<group>";
353+ };
354+ 12230AF223900BB6004A01E5 /* Establishments api */ = {
355+ isa = PBXGroup;
356+ children = (
357+ 12230AF323900BCB004A01E5 /* EstablishmentService.swift */,
358+ 12230AF523900D32004A01E5 /* Resolvers */,
359+ );
360+ path = "Establishments api";
361+ sourceTree = "<group>";
362+ };
363+ 12230AF523900D32004A01E5 /* Resolvers */ = {
364+ isa = PBXGroup;
365+ children = (
366+ 12230AF623900D44004A01E5 /* EstablishmentResolver.swift */,
367+ );
368+ path = Resolvers;
369+ sourceTree = "<group>";
370+ };
371+ 12230AF823901000004A01E5 /* DB */ = {
372+ isa = PBXGroup;
373+ children = (
374+ 12230AF923901029004A01E5 /* DataStorage.swift */,
375+ 12230AF023900974004A01E5 /* TotalStorage.swift */,
376+ );
377+ path = DB;
378+ sourceTree = "<group>";
379+ };
233 123615D22355141D00D1122A /* Views */ = {
380 123615D22355141D00D1122A /* Views */ = {
234 isa = PBXGroup;
381 isa = PBXGroup;
235 children = (
382 children = (
@@ -259,6 +406,35 @@
259 path = Cells;
406 path = Cells;
260 sourceTree = "<group>";
407 sourceTree = "<group>";
261 };
408 };
409+ 124D007D2372229500AE76B9 /* Reservations api */ = {
410+ isa = PBXGroup;
411+ children = (
412+ 124D0080237222C900AE76B9 /* ReservationsService.swift */,
413+ 124D00822372233000AE76B9 /* Resolvers */,
414+ );
415+ path = "Reservations api";
416+ sourceTree = "<group>";
417+ };
418+ 124D00822372233000AE76B9 /* Resolvers */ = {
419+ isa = PBXGroup;
420+ children = (
421+ 124D007E237222B200AE76B9 /* ReservationsResolver.swift */,
422+ 12B4447B238EF25C000B6B16 /* CreateReservationResolver.swift */,
423+ 1212048B23914CFD00CAF162 /* DeleteReservationResolver.swift */,
424+ 1212048D23915A0A00CAF162 /* ChangeReservationResolver.swift */,
425+ );
426+ path = Resolvers;
427+ sourceTree = "<group>";
428+ };
429+ 125AE51B2395582900F847BD /* change */ = {
430+ isa = PBXGroup;
431+ children = (
432+ 125AE51C2395583E00F847BD /* ChangeReservationCoordinator.swift */,
433+ 125AE51E2395585300F847BD /* ChangeReservationViewController.swift */,
434+ );
435+ path = "change ";
436+ sourceTree = "<group>";
437+ };
262 12838EB923679AEB00CEF108 /* API */ = {
438 12838EB923679AEB00CEF108 /* API */ = {
263 isa = PBXGroup;
439 isa = PBXGroup;
264 children = (
440 children = (
@@ -267,11 +443,46 @@
267 12838EAF236777D400CEF108 /* ServerError.swift */,
443 12838EAF236777D400CEF108 /* ServerError.swift */,
268 12838EB523677FB900CEF108 /* ApiRequest.swift */,
444 12838EB523677FB900CEF108 /* ApiRequest.swift */,
269 12838EB72367834900CEF108 /* MyCodable.swift */,
445 12838EB72367834900CEF108 /* MyCodable.swift */,
446+ 12230AF223900BB6004A01E5 /* Establishments api */,
447+ 124D007D2372229500AE76B9 /* Reservations api */,
270 12118B9A2368187B006BAEE3 /* Authorization api */,
448 12118B9A2368187B006BAEE3 /* Authorization api */,
271 );
449 );
272 path = API;
450 path = API;
273 sourceTree = "<group>";
451 sourceTree = "<group>";
274 };
452 };
453+ 12BD95AE237EBE52009614D8 /* Maps */ = {
454+ isa = PBXGroup;
455+ children = (
456+ 12A075FE237358F200D749BB /* MapView.swift */,
457+ 12230AED238FD8D5004A01E5 /* 1 */,
458+ 12230AEE238FD8DE004A01E5 /* 2 */,
459+ );
460+ path = Maps;
461+ sourceTree = "<group>";
462+ };
463+ 12BD95B3237EC231009614D8 /* Steps */ = {
464+ isa = PBXGroup;
465+ children = (
466+ 125AE51B2395582900F847BD /* change */,
467+ 12230AEF239008F8004A01E5 /* Common */,
468+ 12BD95B4237EC23A009614D8 /* 1 */,
469+ 12F9652823868E4900FCA696 /* 2 */,
470+ 120BFC7A2389194B001EBE89 /* 3 */,
471+ );
472+ path = Steps;
473+ sourceTree = "<group>";
474+ };
475+ 12BD95B4237EC23A009614D8 /* 1 */ = {
476+ isa = PBXGroup;
477+ children = (
478+ 12A075F62373535C00D749BB /* FirstStepReservationViewController.swift */,
479+ 12A075FC237357E900D749BB /* FirstStepReservationCoordinator.swift */,
480+ 12BD95B1237EC22B009614D8 /* FirstStepView.swift */,
481+ 12BD95AF237EBEDE009614D8 /* FirstStepView.xib */,
482+ );
483+ path = 1;
484+ sourceTree = "<group>";
485+ };
275 12C72EDB235367CF00AD7004 /* Tab bar */ = {
486 12C72EDB235367CF00AD7004 /* Tab bar */ = {
276 isa = PBXGroup;
487 isa = PBXGroup;
277 children = (
488 children = (
@@ -329,6 +540,17 @@
329 path = Code;
540 path = Code;
330 sourceTree = "<group>";
541 sourceTree = "<group>";
331 };
542 };
543+ 12F9652823868E4900FCA696 /* 2 */ = {
544+ isa = PBXGroup;
545+ children = (
546+ 12230AFB239034D3004A01E5 /* SecondStepReservationViewController.swift */,
547+ 12F9652D23869F3100FCA696 /* SecondStepReservationCoordinator.swift */,
548+ 12F9652B23868E7200FCA696 /* SecondStepView.swift */,
549+ 12F9652923868E6000FCA696 /* SecondStepView.xib */,
550+ );
551+ path = 2;
552+ sourceTree = "<group>";
553+ };
332 F30369B623367B2300A8EA84 /* Supporting Files */ = {
554 F30369B623367B2300A8EA84 /* Supporting Files */ = {
333 isa = PBXGroup;
555 isa = PBXGroup;
334 children = (
556 children = (
@@ -368,6 +590,8 @@
368 F3DC5A00233E896300B5E751 /* ButtonStyle.swift */,
590 F3DC5A00233E896300B5E751 /* ButtonStyle.swift */,
369 F3895F52233D5EEB00FA6A37 /* BlackButtonStyle.swift */,
591 F3895F52233D5EEB00FA6A37 /* BlackButtonStyle.swift */,
370 F3DC5A04233E89D500B5E751 /* Button.swift */,
592 F3DC5A04233E89D500B5E751 /* Button.swift */,
593+ 12FC40372382C93C00AB593B /* TableButtonStyle.swift */,
594+ 12FC40392382CB6F00AB593B /* TableButton.swift */,
371 );
595 );
372 path = Components;
596 path = Components;
373 sourceTree = "<group>";
597 sourceTree = "<group>";
@@ -394,6 +618,8 @@
394 children = (
618 children = (
395 F3851B2F2340A513009EE0B6 /* RegistationViewModel.swift */,
619 F3851B2F2340A513009EE0B6 /* RegistationViewModel.swift */,
396 12B6A610235B8EC500898B31 /* User.swift */,
620 12B6A610235B8EC500898B31 /* User.swift */,
621+ 124D007B23721FD400AE76B9 /* Reservation.swift */,
622+ 12D8FA30237F08C700305F57 /* AllReservations.swift */,
397 );
623 );
398 path = Models;
624 path = Models;
399 sourceTree = "<group>";
625 sourceTree = "<group>";
@@ -486,10 +712,13 @@
486 F3FC7DCB2315BE610080D851 /* Hookah Tau */ = {
712 F3FC7DCB2315BE610080D851 /* Hookah Tau */ = {
487 isa = PBXGroup;
713 isa = PBXGroup;
488 children = (
714 children = (
489− 12FE4041236B8B050012391E /* DataStorage.swift */,
715+ 12230AF823901000004A01E5 /* DB */,
490 F3FC7DCC2315BE610080D851 /* AppDelegate.swift */,
716 F3FC7DCC2315BE610080D851 /* AppDelegate.swift */,
491 F3DC59FE233E893400B5E751 /* Extensions+UIFont.swift */,
717 F3DC59FE233E893400B5E751 /* Extensions+UIFont.swift */,
492 F31E20C62348DDB900BEA215 /* Extensions+UIView.swift */,
718 F31E20C62348DDB900BEA215 /* Extensions+UIView.swift */,
719+ 12050568238048CE00801618 /* Extensions+Date.swift */,
720+ 1205056A2380588C00801618 /* Extenstions+IBDesignable.swift */,
721+ 125AE5202395753400F847BD /* HFunc.swift */,
493 12838EB923679AEB00CEF108 /* API */,
722 12838EB923679AEB00CEF108 /* API */,
494 F30369BC2336861100A8EA84 /* Models */,
723 F30369BC2336861100A8EA84 /* Models */,
495 F3199E59233FD7F700F3C17A /* Views */,
724 F3199E59233FD7F700F3C17A /* Views */,
@@ -631,10 +860,18 @@
631 files = (
860 files = (
632 F3199E5B233FE08200F3C17A /* PhoneView.xib in Resources */,
861 F3199E5B233FE08200F3C17A /* PhoneView.xib in Resources */,
633 12DBEEB223539F2100AF1BB6 /* Client.storyboard in Resources */,
862 12DBEEB223539F2100AF1BB6 /* Client.storyboard in Resources */,
863+ 12D8FA2D237F003800305F57 /* DateView.xib in Resources */,
634 12387337234BB98700D1F1AB /* CodeView.xib in Resources */,
864 12387337234BB98700D1F1AB /* CodeView.xib in Resources */,
635 12B6A615235BB36C00898B31 /* ChangeView.xib in Resources */,
865 12B6A615235BB36C00898B31 /* ChangeView.xib in Resources */,
636 F3851B2C2340A280009EE0B6 /* TitleTextView.xib in Resources */,
866 F3851B2C2340A280009EE0B6 /* TitleTextView.xib in Resources */,
867+ 12F9652A23868E6000FCA696 /* SecondStepView.xib in Resources */,
868+ 120BFC7E23891975001EBE89 /* ThirdStepView.xib in Resources */,
869+ 12230AEA238FD8B3004A01E5 /* MapView2.xib in Resources */,
637 1246B71E235CDF8A004CBFA1 /* ReservationView.xib in Resources */,
870 1246B71E235CDF8A004CBFA1 /* ReservationView.xib in Resources */,
871+ 12BD95B6237ED8AC009614D8 /* TimePointView.xib in Resources */,
872+ 12A075F9237353F500D749BB /* MapView1.xib in Resources */,
873+ 12A075FB2373561A00D749BB /* Reservation.storyboard in Resources */,
874+ 12BD95B0237EBEDF009614D8 /* FirstStepView.xib in Resources */,
638 F30369B5233679EA00A8EA84 /* LaunchScreen.storyboard in Resources */,
875 F30369B5233679EA00A8EA84 /* LaunchScreen.storyboard in Resources */,
639 1246B717235CD186004CBFA1 /* NoReservationsView.xib in Resources */,
876 1246B717235CD186004CBFA1 /* NoReservationsView.xib in Resources */,
640 F3FC7DD42315BE630080D851 /* Assets.xcassets in Resources */,
877 F3FC7DD42315BE630080D851 /* Assets.xcassets in Resources */,
@@ -666,6 +903,8 @@
666 buildActionMask = 2147483647;
903 buildActionMask = 2147483647;
667 files = (
904 files = (
668 12EA99482362B684005D9FE9 /* AddresViewController.swift in Sources */,
905 12EA99482362B684005D9FE9 /* AddresViewController.swift in Sources */,
906+ 124D007F237222B200AE76B9 /* ReservationsResolver.swift in Sources */,
907+ 12230AF723900D44004A01E5 /* EstablishmentResolver.swift in Sources */,
669 1246B719235CD3AD004CBFA1 /* NoReservationsView.swift in Sources */,
908 1246B719235CD3AD004CBFA1 /* NoReservationsView.swift in Sources */,
670 F3895F4A233D323700FA6A37 /* CodeCoordinator.swift in Sources */,
909 F3895F4A233D323700FA6A37 /* CodeCoordinator.swift in Sources */,
671 12838EB4236779C700CEF108 /* ApiResolver.swift in Sources */,
910 12838EB4236779C700CEF108 /* ApiResolver.swift in Sources */,
@@ -673,22 +912,38 @@
673 123615D12355141600D1122A /* ProfileView.swift in Sources */,
912 123615D12355141600D1122A /* ProfileView.swift in Sources */,
674 12F73B022357AD7B007D4476 /* ProfileChangeViewController.swift in Sources */,
913 12F73B022357AD7B007D4476 /* ProfileChangeViewController.swift in Sources */,
675 F3851B2E2340A444009EE0B6 /* TitleTextView.swift in Sources */,
914 F3851B2E2340A444009EE0B6 /* TitleTextView.swift in Sources */,
915+ 125AE51F2395585300F847BD /* ChangeReservationViewController.swift in Sources */,
676 12EA99462362B674005D9FE9 /* AddressCoordinator.swift in Sources */,
916 12EA99462362B674005D9FE9 /* AddressCoordinator.swift in Sources */,
677 12B6A613235B9B4300898B31 /* BaseViewController.swift in Sources */,
917 12B6A613235B9B4300898B31 /* BaseViewController.swift in Sources */,
918+ 12230AFA23901029004A01E5 /* DataStorage.swift in Sources */,
678 F3FC7DFF2315C8D70080D851 /* NameCoordinator.swift in Sources */,
919 F3FC7DFF2315C8D70080D851 /* NameCoordinator.swift in Sources */,
920+ 120BFC7C23891965001EBE89 /* ThirdStepView.swift in Sources */,
679 F3FC7DCF2315BE610080D851 /* NameViewController.swift in Sources */,
921 F3FC7DCF2315BE610080D851 /* NameViewController.swift in Sources */,
680 12838EB82367834900CEF108 /* MyCodable.swift in Sources */,
922 12838EB82367834900CEF108 /* MyCodable.swift in Sources */,
681 F3DC5A05233E89D500B5E751 /* Button.swift in Sources */,
923 F3DC5A05233E89D500B5E751 /* Button.swift in Sources */,
682 F3FC7DFB2315C25D0080D851 /* ApplicationCoordinator.swift in Sources */,
924 F3FC7DFB2315C25D0080D851 /* ApplicationCoordinator.swift in Sources */,
925+ 12FC403A2382CB6F00AB593B /* TableButton.swift in Sources */,
683 12EB698123661CB300E4D1CE /* AddressCell.swift in Sources */,
926 12EB698123661CB300E4D1CE /* AddressCell.swift in Sources */,
684 F3895F48233D2EEA00FA6A37 /* CodeSmsViewController.swift in Sources */,
927 F3895F48233D2EEA00FA6A37 /* CodeSmsViewController.swift in Sources */,
685 12219CEF2353A63F0057DDEE /* ReservationsCoordinator.swift in Sources */,
928 12219CEF2353A63F0057DDEE /* ReservationsCoordinator.swift in Sources */,
929+ 12230AF423900BCB004A01E5 /* EstablishmentService.swift in Sources */,
930+ 12A07601237359BB00D749BB /* MapView1.swift in Sources */,
931+ 125AE5212395753400F847BD /* HFunc.swift in Sources */,
932+ 12BD95B8237EDB01009614D8 /* TimePointView.swift in Sources */,
686 12838EB2236779A000CEF108 /* AuthResolver.swift in Sources */,
933 12838EB2236779A000CEF108 /* AuthResolver.swift in Sources */,
687− 12FE4042236B8B050012391E /* DataStorage.swift in Sources */,
934+ 12A075F72373535C00D749BB /* FirstStepReservationViewController.swift in Sources */,
688 1246B71C235CDF3A004CBFA1 /* ReservationCell.swift in Sources */,
935 1246B71C235CDF3A004CBFA1 /* ReservationCell.swift in Sources */,
936+ 1212048C23914CFD00CAF162 /* DeleteReservationResolver.swift in Sources */,
937+ 12A075FD237357E900D749BB /* FirstStepReservationCoordinator.swift in Sources */,
938+ 124D0081237222C900AE76B9 /* ReservationsService.swift in Sources */,
689 1246B720235CDF9E004CBFA1 /* ReservationView.swift in Sources */,
939 1246B720235CDF9E004CBFA1 /* ReservationView.swift in Sources */,
940+ 12050569238048CE00801618 /* Extensions+Date.swift in Sources */,
941+ 124D007C23721FD400AE76B9 /* Reservation.swift in Sources */,
942+ 12D8FA2F237F00E200305F57 /* DateView.swift in Sources */,
943+ 12F9652E23869F3100FCA696 /* SecondStepReservationCoordinator.swift in Sources */,
690 F3895F4E233D348B00FA6A37 /* PhoneCoordinator.swift in Sources */,
944 F3895F4E233D348B00FA6A37 /* PhoneCoordinator.swift in Sources */,
691 12B6A617235BB37D00898B31 /* ChangeView.swift in Sources */,
945 12B6A617235BB37D00898B31 /* ChangeView.swift in Sources */,
946+ 12230AEC238FD8C5004A01E5 /* MapView2.swift in Sources */,
692 F3FC7DCD2315BE610080D851 /* AppDelegate.swift in Sources */,
947 F3FC7DCD2315BE610080D851 /* AppDelegate.swift in Sources */,
693 12838EB623677FB900CEF108 /* ApiRequest.swift in Sources */,
948 12838EB623677FB900CEF108 /* ApiRequest.swift in Sources */,
694 12118B9E23682049006BAEE3 /* PhoneCodeResolver.swift in Sources */,
949 12118B9E23682049006BAEE3 /* PhoneCodeResolver.swift in Sources */,
@@ -696,6 +951,8 @@
696 F3FC7DFD2315C4710080D851 /* BaseCoordinator.swift in Sources */,
951 F3FC7DFD2315C4710080D851 /* BaseCoordinator.swift in Sources */,
697 F3DC59FF233E893400B5E751 /* Extensions+UIFont.swift in Sources */,
952 F3DC59FF233E893400B5E751 /* Extensions+UIFont.swift in Sources */,
698 F3895F53233D5EEB00FA6A37 /* BlackButtonStyle.swift in Sources */,
953 F3895F53233D5EEB00FA6A37 /* BlackButtonStyle.swift in Sources */,
954+ 12F9652C23868E7200FCA696 /* SecondStepView.swift in Sources */,
955+ 120BFC7923891942001EBE89 /* ThirdStepReservationCoordinator.swift in Sources */,
699 12118B9C23682022006BAEE3 /* RegistrationResolver.swift in Sources */,
956 12118B9C23682022006BAEE3 /* RegistrationResolver.swift in Sources */,
700 F30369C02336925800A8EA84 /* ClientTabbarController.swift in Sources */,
957 F30369C02336925800A8EA84 /* ClientTabbarController.swift in Sources */,
701 F31E20C72348DDB900BEA215 /* Extensions+UIView.swift in Sources */,
958 F31E20C72348DDB900BEA215 /* Extensions+UIView.swift in Sources */,
@@ -705,15 +962,26 @@
705 12EA994E2362FCE8005D9FE9 /* AddressView.swift in Sources */,
962 12EA994E2362FCE8005D9FE9 /* AddressView.swift in Sources */,
706 F3895F4C233D347E00FA6A37 /* PhoneNumberViewController.swift in Sources */,
963 F3895F4C233D347E00FA6A37 /* PhoneNumberViewController.swift in Sources */,
707 12EE4A76234BB8FE005B4D1A /* CodeView.swift in Sources */,
964 12EE4A76234BB8FE005B4D1A /* CodeView.swift in Sources */,
965+ 12230AF123900974004A01E5 /* TotalStorage.swift in Sources */,
966+ 12BD95B2237EC22B009614D8 /* FirstStepView.swift in Sources */,
708 F3EBE2472340FE87000FEE1A /* NameTextView.swift in Sources */,
967 F3EBE2472340FE87000FEE1A /* NameTextView.swift in Sources */,
968+ 120BFC7723891925001EBE89 /* ThirdStepReservationViewController.swift in Sources */,
709 F3DC5A01233E896300B5E751 /* ButtonStyle.swift in Sources */,
969 F3DC5A01233E896300B5E751 /* ButtonStyle.swift in Sources */,
970+ 12A075FF237358F200D749BB /* MapView.swift in Sources */,
971+ 1205056B2380588C00801618 /* Extenstions+IBDesignable.swift in Sources */,
710 12C72EE1235380D400AD7004 /* ProfileClientViewController.swift in Sources */,
972 12C72EE1235380D400AD7004 /* ProfileClientViewController.swift in Sources */,
711 F31E20C92348E0F300BEA215 /* AuthorizationViewController.swift in Sources */,
973 F31E20C92348E0F300BEA215 /* AuthorizationViewController.swift in Sources */,
974+ 1212048E23915A0A00CAF162 /* ChangeReservationResolver.swift in Sources */,
975+ 12230AFC239034D3004A01E5 /* SecondStepReservationViewController.swift in Sources */,
712 F3851B2923409F8A009EE0B6 /* PhoneView.swift in Sources */,
976 F3851B2923409F8A009EE0B6 /* PhoneView.swift in Sources */,
713 12C72EE3235380EB00AD7004 /* ReservationsViewController.swift in Sources */,
977 12C72EE3235380EB00AD7004 /* ReservationsViewController.swift in Sources */,
714 12B6A611235B8EC500898B31 /* User.swift in Sources */,
978 12B6A611235B8EC500898B31 /* User.swift in Sources */,
979+ 12B4447C238EF25C000B6B16 /* CreateReservationResolver.swift in Sources */,
715 12B6A60F235B857A00898B31 /* ProfileChangeCoordinator.swift in Sources */,
980 12B6A60F235B857A00898B31 /* ProfileChangeCoordinator.swift in Sources */,
981+ 12FC40382382C93D00AB593B /* TableButtonStyle.swift in Sources */,
982+ 12D8FA31237F08C700305F57 /* AllReservations.swift in Sources */,
716 12838EB0236777D400CEF108 /* ServerError.swift in Sources */,
983 12838EB0236777D400CEF108 /* ServerError.swift in Sources */,
984+ 125AE51D2395583E00F847BD /* ChangeReservationCoordinator.swift in Sources */,
717 );
985 );
718 runOnlyForDeploymentPostprocessing = 0;
986 runOnlyForDeploymentPostprocessing = 0;
719 };
987 };
Hookah Tau/API/APIClient.swift+5
@@ -50,6 +50,7 @@ class APIClient {
50 }
50 }
51 case 422:
51 case 422:
52 if let data = response.data, let error = SE.fromJSONToSelf(data: data) {
52 if let data = response.data, let error = SE.fromJSONToSelf(data: data) {
53+ print(error)
53 return GeneralError.serverError(error)
54 return GeneralError.serverError(error)
54 }
55 }
55
56
@@ -59,6 +60,10 @@ class APIClient {
59 }
60 }
60 }
61 }
61
62
63+ if let _ = response.error {
64+ return GeneralError.alamofireError
65+ }
66+
62 return GeneralError.somethingWentCompletelyWrong
67 return GeneralError.somethingWentCompletelyWrong
63 }
68 }
64}
69}
Hookah Tau/API/ApiRequest.swift+1−1
@@ -34,7 +34,7 @@ class ApiRequest {
34 let url = URL(string: APIClient.BaseUrls.staging + (resolver.groupName ?? "") + resolver.name)!
34 let url = URL(string: APIClient.BaseUrls.staging + (resolver.groupName ?? "") + resolver.name)!
35 self.request = URLRequest(url: url)
35 self.request = URLRequest(url: url)
36
36
37− self.request.httpBody = resolver.parameters().toJSONData()
37+ self.request.httpBody = resolver.parameters()?.toJSONData()
38 self.request.setValue("application/json;charset=utf-8",
38 self.request.setValue("application/json;charset=utf-8",
39 forHTTPHeaderField: "Content-Type")
39 forHTTPHeaderField: "Content-Type")
40 self.request.httpMethod = httpMethod.rawValue
40 self.request.httpMethod = httpMethod.rawValue
Hookah Tau/API/ApiResolver.swift+7−1
@@ -15,5 +15,11 @@ protocol ApiResolver: class {
15 var groupName: String? { get }
15 var groupName: String? { get }
16
16
17 /// Parameter for request
17 /// Parameter for request
18− func parameters() -> MyCodable
18+ func parameters() -> MyCodable?
19+}
20+
21+extension ApiResolver {
22+ var groupName: String? { return nil }
23+
24+ func parameters() -> MyCodable? { return nil }
19}
25}
Hookah Tau/API/Authorization api/AuthorizationService.swift+3−2
@@ -100,10 +100,11 @@ class AuthorizationService {
100
100
101 private func setCookies(response: AFDataResponse<Data?>) {
101 private func setCookies(response: AFDataResponse<Data?>) {
102 let fields = response.response?.allHeaderFields as? [String :String]
102 let fields = response.response?.allHeaderFields as? [String :String]
103− guard let fieldss = fields, let url = response.response?.url else {
103+ guard let fieldss = fields, let url = URL(string: APIClient.BaseUrls.staging) else {
104 return
104 return
105 }
105 }
106 let cookies = HTTPCookie.cookies(withResponseHeaderFields: fieldss, for: url)
106 let cookies = HTTPCookie.cookies(withResponseHeaderFields: fieldss, for: url)
107− HTTPCookieStorage.shared.setCookie(cookies[0])
107+ HTTPCookieStorage.shared.setCookies(cookies, for: url, mainDocumentURL: nil)
108+ DataStorage.standard.setCookies(cookies, forURL: url)
108 }
109 }
109}
110}
Hookah Tau/API/Authorization api/Resolvers/AuthResolver.swift+1−1
@@ -38,7 +38,7 @@ class AuthResolver<Response: MyCodable>: ApiResolver {
38 self.phoneNumber = phoneNumber
38 self.phoneNumber = phoneNumber
39 }
39 }
40
40
41− func parameters() -> MyCodable {
41+ func parameters() -> MyCodable? {
42 return Request(phoneNumber: phoneNumber)
42 return Request(phoneNumber: phoneNumber)
43 }
43 }
44
44
Hookah Tau/API/Authorization api/Resolvers/PhoneCodeResolver.swift+1−1
@@ -37,7 +37,7 @@ class PhoneCodeResolver<Response: MyCodable>: ApiResolver {
37 self.code = code
37 self.code = code
38 }
38 }
39
39
40− func parameters() -> MyCodable {
40+ func parameters() -> MyCodable? {
41 return Request(phoneNumber: phoneNumber,
41 return Request(phoneNumber: phoneNumber,
42 code: code)
42 code: code)
43 }
43 }
Hookah Tau/API/Authorization api/Resolvers/RegistrationResolver.swift+1−1
@@ -40,7 +40,7 @@ class RegistrationResolver<Response: MyCodable>: ApiResolver {
40 self.phoneNumber = phoneNumber
40 self.phoneNumber = phoneNumber
41 }
41 }
42
42
43− func parameters() -> MyCodable {
43+ func parameters() -> MyCodable? {
44 return Request(name: uname,
44 return Request(name: uname,
45 phoneNumber: phoneNumber,
45 phoneNumber: phoneNumber,
46 code: code)
46 code: code)
Hookah Tau/API/Establishments api/EstablishmentService.swiftnew file+39
@@ -0,0 +1,39 @@
1+//
2+// EstablishmentService.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 28/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+class EstablishmentSevice {
12+ private var apiClient: APIClient
13+
14+ init(apiClient: APIClient) {
15+ self.apiClient = apiClient
16+ }
17+
18+ func loadAdmins(completion: @escaping ((Result<[Int: String], GeneralError>) -> Void)) {
19+ let resolver = EstablishmentResolver<[Int: String]>()
20+ let request = ApiRequest(resolver: resolver, httpMethod: .get)
21+
22+ apiClient.load(request: request.request) { result in
23+ switch result {
24+ case .failure(let err):
25+ completion(.failure(err))
26+ case .success(let response):
27+ guard
28+ let data = response.data,
29+ let decondedData = try? JSONDecoder().decode([Int: String].self, from: data)
30+ else {
31+ completion(.failure(.decodeError))
32+ return
33+ }
34+
35+ completion(.success(decondedData))
36+ }
37+ }
38+ }
39+}
Hookah Tau/API/Establishments api/Resolvers/EstablishmentResolver.swiftnew file+24
@@ -0,0 +1,24 @@
1+//
2+// EstablishmentReslver.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 28/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+
12+class EstablishmentResolver<Response>: ApiResolver {
13+ var name: String {
14+ return "/admins"
15+ }
16+
17+ var groupName: String? {
18+ return "/establishments"
19+ }
20+
21+ func targetClass() -> Response.Type {
22+ return Response.self
23+ }
24+}
Hookah Tau/API/MyCodable.swift+12−2
@@ -16,10 +16,20 @@ protocol MyCodable: Codable {
16
16
17extension MyCodable {
17extension MyCodable {
18 func toJSONData() -> Data? {
18 func toJSONData() -> Data? {
19+ let encoder = JSONEncoder()
20+ encoder.dateEncodingStrategy = .formatted(DateFormatter.iso8601Full)
19− return try? JSONEncoder().encode(self)
21+ return try? encoder.encode(self)
20 }
22 }
21
23
22 static func fromJSONToSelf(data: Data) -> Self? {
24 static func fromJSONToSelf(data: Data) -> Self? {
25+ let decoder = JSONDecoder()
26+ decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
27+ return try? decoder.decode(self, from: data)
28+ }
29+
30+ static func fromJSONToSelfArray<T: MyCodable>(data : Data) -> [T]? {
31+ let decoder = JSONDecoder()
32+ decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
23− return try? JSONDecoder().decode(self, from: data)
33+ return try? decoder.decode([T].self, from: data)
24 }
34 }
25}
35}
Hookah Tau/API/Reservations api/ReservationsService.swiftnew file+148
@@ -0,0 +1,148 @@
1+//
2+// ReservationsService.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 06/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+import Alamofire
11+
12+/// Слой методов для авторизации пользователя в приложении
13+class ReservationsService {
14+ private var apiClient: APIClient
15+
16+ init(apiClient: APIClient) {
17+ self.apiClient = apiClient
18+ }
19+
20+ /// Gets all reservations made by the current user.
21+ func loadUsersReservations(completion: @escaping (Result<[Reservation], GeneralError>) -> Void) {
22+ let resolver = ReservationsResolver<ReservationsResponce>()
23+
24+ let request = ApiRequest(resolver: resolver, httpMethod: .get)
25+ apiClient.load(request: request.request) { (result) in
26+ switch result {
27+ case .failure(let err):
28+ completion(.failure(err))
29+ case .success(let response):
30+ guard
31+ let d = response.data,
32+ let decodedData = resolver.targetClass().fromJSONToSelf(data: d)
33+ else {
34+ completion(.failure(GeneralError.decodeError))
35+ return
36+ }
37+
38+ completion(.success(decodedData.reservations))
39+ }
40+ }
41+ }
42+
43+ func deleteReservation(uuid: String, completion: @escaping ((Bool) -> Void)) {
44+ let resolver = DeleteReservationResolver(uuid: uuid)
45+ let request = ApiRequest(resolver: resolver, httpMethod: .delete)
46+
47+ apiClient.load(request: request.request) { result in
48+ switch result {
49+ case .failure:
50+ completion(false)
51+ return
52+ case .success:
53+ completion(true)
54+ return
55+ }
56+ }
57+ }
58+
59+ func updateReservation(startTime: Date,
60+ numberOfGuests: Int,
61+ endTime: Date,
62+ uuid: String,
63+ completion: @escaping ((Bool) -> Void)) {
64+
65+ let reservation = ChangeReservationResolver.Request(startTime: startTime,
66+ uuid: uuid,
67+ numberOfGuests: numberOfGuests,
68+ endTime: endTime)
69+
70+ let resolver = ChangeReservationResolver(data: reservation)
71+ let request = ApiRequest(resolver: resolver, httpMethod: .put)
72+
73+ apiClient.load(request: request.request) { result in
74+ switch result {
75+ case .failure:
76+ completion(false)
77+ return
78+ case .success:
79+ completion(true)
80+ return
81+ }
82+ }
83+ }
84+
85+
86+ func getAllReservations(establishmentID: Int,
87+ completion: @escaping ((Result<AllReservations, GeneralError>) -> Void)) {
88+ let resolver = AllReservationsResolver<AllReservations>(establishmentID: establishmentID)
89+
90+ let request = ApiRequest(resolver: resolver, httpMethod: .get)
91+
92+ apiClient.load(request: request.request) { result in
93+ switch result {
94+ case .failure(let err):
95+ completion(.failure(err))
96+ case .success(let response):
97+ guard
98+ let d = response.data,
99+ let decodedData = resolver.targetClass().fromJSONToSelf(data: d)
100+ else {
101+ completion(.failure(GeneralError.decodeError))
102+ return
103+ }
104+
105+ completion(.success(decodedData))
106+ }
107+ }
108+ }
109+
110+ func createReservation(data: ReservationData,
111+ completion: @escaping ((Result<Reservation, GeneralError>) -> Void)) {
112+ // for 1 time use
113+ struct Response: MyCodable {
114+ var reservationUUID: String
115+ }
116+
117+ // local map for output
118+ func map(data: ReservationData, id: String) -> Reservation {
119+
120+ return Reservation(uuid: id,
121+ establishment: data.establishment,
122+ startTime: data.startTime,
123+ endTime: data.endTime,
124+ numberOfGuests: data.numberOfGuests,
125+ reservedTable: data.reservedTable)
126+ }
127+
128+ let resolver = CreateReservationResolver<Response>(data: data)
129+ let request = ApiRequest(resolver: resolver, httpMethod: .post)
130+
131+ apiClient.load(request: request.request) { result in
132+ switch result {
133+ case .failure(let err):
134+ completion(.failure(err))
135+ case .success(let response):
136+ guard
137+ let d = response.data,
138+ let id = resolver.targetClass().fromJSONToSelf(data: d)?.reservationUUID
139+ else {
140+ completion(.failure(GeneralError.decodeError))
141+ return
142+ }
143+
144+ completion(.success(map(data: data, id: id)))
145+ }
146+ }
147+ }
148+}
Hookah Tau/API/Reservations api/Resolvers/ChangeReservationResolver.swiftnew file+35
@@ -0,0 +1,35 @@
1+//
2+// ChangeReservationResolver.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 29/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+class ChangeReservationResolver: ApiResolver {
12+
13+ /// Структура запроса с возможными данными для
14+ /// изменением бронирования
15+ struct Request: MyCodable {
16+ var startTime: Date
17+ var uuid: String
18+ var numberOfGuests: Int
19+ var endTime: Date
20+ }
21+
22+ var name: String {
23+ return "/reservations"
24+ }
25+
26+ var data: Request
27+
28+ init(data: Request) {
29+ self.data = data
30+ }
31+
32+ func parameters() -> MyCodable? {
33+ return data
34+ }
35+}
Hookah Tau/API/Reservations api/Resolvers/CreateReservationResolver.swiftnew file+30
@@ -0,0 +1,30 @@
1+//
2+// CreateReservationResolver.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 27/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+class CreateReservationResolver<Response: Codable>: ApiResolver {
12+
13+ var name: String {
14+ return "/reservations"
15+ }
16+
17+ var data: ReservationData
18+
19+ init(data: ReservationData) {
20+ self.data = data
21+ }
22+
23+ func parameters() -> MyCodable? {
24+ return data
25+ }
26+
27+ func targetClass() -> Response.Type {
28+ return Response.self
29+ }
30+}
Hookah Tau/API/Reservations api/Resolvers/DeleteReservationResolver.swiftnew file+31
@@ -0,0 +1,31 @@
1+//
2+// DeleteReservationResolver.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 29/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+
12+class DeleteReservationResolver: ApiResolver {
13+
14+ struct Request: MyCodable {
15+ var reservationUUID: String
16+ }
17+
18+ var name: String {
19+ return "/reservations"
20+ }
21+
22+ var uuid: String
23+
24+ init(uuid: String) {
25+ self.uuid = uuid
26+ }
27+
28+ func parameters() -> MyCodable? {
29+ return Request(reservationUUID: uuid)
30+ }
31+}
Hookah Tau/API/Reservations api/Resolvers/ReservationsResolver.swiftnew file+46
@@ -0,0 +1,46 @@
1+//
2+// ReservationsResolver.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 06/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+struct ReservationsResponce: MyCodable {
10+ var reservations: [Reservation]
11+}
12+
13+class ReservationsResolver<Response: MyCodable>: ApiResolver {
14+ var name: String {
15+ return "/reservations"
16+ }
17+
18+ func targetClass() -> Response.Type {
19+ return Response.self
20+ }
21+}
22+
23+class AllReservationsResolver<Response: Codable>: ApiResolver {
24+
25+ struct Request: MyCodable {
26+ var establishmentUUID: Int
27+ }
28+
29+ var name: String {
30+ return "/all/\(self.establishmentID)"
31+ }
32+
33+ var groupName: String? {
34+ return "/reservations"
35+ }
36+
37+ var establishmentID: Int
38+
39+ init(establishmentID: Int) {
40+ self.establishmentID = establishmentID
41+ }
42+
43+ func targetClass() -> Response.Type {
44+ return Response.self
45+ }
46+}
Hookah Tau/API/ServerError.swift+1
@@ -18,4 +18,5 @@ enum GeneralError: Error {
18 case noData
18 case noData
19 case Error400
19 case Error400
20 case somethingWentCompletelyWrong
20 case somethingWentCompletelyWrong
21+ case alamofireError
21}
22}
Hookah Tau/AppDelegate.swift+1−2
@@ -21,14 +21,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
21 window?.makeKeyAndVisible()
21 window?.makeKeyAndVisible()
22
22
23 let navController = UINavigationController()
23 let navController = UINavigationController()
24− window?.rootViewController = navController
25
24
26 applicationCoordinator = ApplicationCoordinator(navigationController: navController)
25 applicationCoordinator = ApplicationCoordinator(navigationController: navController)
27 applicationCoordinator?.start()
26 applicationCoordinator?.start()
28
27
29 return true
28 return true
30 }
29 }
31−
30+
32 func applicationWillResignActive(_ application: UIApplication) {
31 func applicationWillResignActive(_ application: UIApplication) {
33 // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
32 // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
34 // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
33 // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
Hookah Tau/Components/BlackButtonStyle.swift+8
@@ -39,6 +39,14 @@ class BlackButtonStyle: NSObject {
39 button.addSubviewThatFills(view)
39 button.addSubviewThatFills(view)
40 }
40 }
41
41
42+ func changeToBookedState(button: Button) {
43+ TableStyle.setStripes(for: button)
44+ }
45+
46+ func changeToAvailiableState(button: Button) {
47+ button.layer.sublayers?.removeAll()
48+ }
49+
42 func backToNormalStyle(button: Button) {
50 func backToNormalStyle(button: Button) {
43 subviewLayer?.removeFromSuperview()
51 subviewLayer?.removeFromSuperview()
44 }
52 }
Hookah Tau/Components/Button.swift+18−1
@@ -22,7 +22,14 @@ class Button: UIButton {
22
22
23 override var isEnabled: Bool {
23 override var isEnabled: Bool {
24 didSet {
24 didSet {
25− //alpha = isEnabled ? 1 : 0.8
25+ alpha = isEnabled ? 1 : 0.8
26+ }
27+ }
28+
29+ /// State when chosen table is Booked
30+ public var availiable = true {
31+ willSet {
32+ willUpdateBookingState(newValue: availiable)
26 }
33 }
27 }
34 }
28
35
@@ -43,4 +50,14 @@ class Button: UIButton {
43 style?.backToNormalStyle(button: self)
50 style?.backToNormalStyle(button: self)
44 }
51 }
45 }
52 }
53+
54+ private func willUpdateBookingState(newValue avaliable: Bool) {
55+ isEnabled = avaliable
56+
57+// if availiable {
58+// style?.changeToAvailiableState(button: self)
59+// } else {
60+// style?.changeToBookedState(button: self)
61+// }
62+ }
46}
63}
Hookah Tau/Components/TableButton.swiftnew file+54
@@ -0,0 +1,54 @@
1+//
2+// TableButton.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 18/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class TableButton: UIButton {
12+
13+ var style: TableButtonStyle?
14+
15+ var isChosen: Bool = false {
16+ didSet {
17+ if isChosen {
18+ style?.setSelected(button: self)
19+ } else {
20+ style?.setUnselected(button: self)
21+ }
22+ }
23+ }
24+
25+ var isBooked: Bool = false {
26+ didSet {
27+ if !isBooked {
28+ style?.setAvaliable(button: self)
29+ } else {
30+ style?.setBooked(button: self)
31+ }
32+ }
33+ }
34+
35+ override func awakeFromNib() {
36+ super.awakeFromNib()
37+ }
38+
39+ func select() {
40+ isChosen = true
41+ }
42+
43+ func active() {
44+ isBooked = false
45+ }
46+
47+ func inactive() {
48+ isBooked = true
49+ }
50+
51+ func unselect() {
52+ isChosen = false
53+ }
54+}
Hookah Tau/Components/TableButtonStyle.swiftnew file+87
@@ -0,0 +1,87 @@
1+//
2+// MapButtonStyle.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 18/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class TableStyle {
12+
13+ static func setStripes(for view: UIView) {
14+ let replicationLayer = createReplicatorLayer()
15+ replicationLayer.frame = view.bounds
16+ replicationLayer.frame.origin.x = -100
17+
18+ view.layer.masksToBounds = true
19+ view.layer.addSublayer(replicationLayer)
20+ }
21+
22+ private static func createReplicatorLayer() -> CAReplicatorLayer {
23+ let replicatorLayer = CAReplicatorLayer()
24+
25+ let stripe = CALayer()
26+
27+ stripe.frame = CGRect(x: 0, y: -10, width: 2, height: 500)
28+ stripe.backgroundColor = UIColor.white.cgColor
29+ stripe.transform = CATransform3DMakeRotation(0.52, 0, 0, 1.0)
30+
31+ replicatorLayer.instanceCount = 60
32+ replicatorLayer.instanceTransform = CATransform3DMakeTranslation(20, 0, 0)
33+ replicatorLayer.addSublayer(stripe)
34+
35+ return replicatorLayer
36+ }
37+
38+}
39+
40+
41+class TableButtonStyle {
42+ enum Constants {
43+ static let cornerRadius: CGFloat = 8
44+ static let clearColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0)
45+ }
46+
47+ enum Selection {
48+ static let borderColor: CGColor = #colorLiteral(red: 0.2901960784, green: 0.5647058824, blue: 0.8862745098, alpha: 1)
49+ static let borderWidth: CGFloat = 3
50+ static let fillColor = #colorLiteral(red: 0.2078431373, green: 0.5215686275, blue: 0.8862745098, alpha: 0.5)
51+ }
52+
53+ enum Booked {
54+ static let fillColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.5)
55+ }
56+
57+ func setSelected(button: TableButton) {
58+ button.layer.borderWidth = Selection.borderWidth
59+ button.layer.borderColor = Selection.borderColor
60+ button.backgroundColor = Selection.fillColor
61+ }
62+
63+ func setBooked(button: TableButton) {
64+ button.backgroundColor = Booked.fillColor
65+ }
66+
67+ func setAvaliable(button: TableButton) {
68+ button.layer.sublayers?.removeAll()
69+ button.backgroundColor = button.isChosen ? Selection.fillColor : Constants.clearColor
70+ }
71+
72+ func setUnselected(button: TableButton) {
73+ button.layer.borderWidth = 0
74+ button.backgroundColor = button.isBooked ? Booked.fillColor : Constants.clearColor
75+ }
76+}
77+
78+// MARK: - ButtonStyle
79+
80+extension TableButtonStyle {
81+
82+ func apply(to button: TableButton?) {
83+ button?.layer.cornerRadius = Constants.cornerRadius
84+ button?.style = self
85+ }
86+
87+}
Hookah Tau/Controllers/ApplicationCoordinator.swift+15−5
@@ -10,7 +10,9 @@ import UIKit
10
10
11class ApplicationCoordinator: BaseCoordinator {
11class ApplicationCoordinator: BaseCoordinator {
12
12
13− var launch: LaunchOptions?
13+ var launch: LaunchOptions? {
14+ return LaunchOptions.configure()
15+ }
14
16
15 override func start() {
17 override func start() {
16 guard let launch = launch else { return }
18 guard let launch = launch else { return }
@@ -27,13 +29,11 @@ class ApplicationCoordinator: BaseCoordinator {
27
29
28 required init(navigationController: UINavigationController?) {
30 required init(navigationController: UINavigationController?) {
29 super.init(navigationController: navigationController)
31 super.init(navigationController: navigationController)
30− self.launch = LaunchOptions.configure()
31 }
32 }
32
33
33 private func runAuthFlow() {
34 private func runAuthFlow() {
34 let phoneCoordinator = PhoneCoordinator(navigationController: navigationController)
35 let phoneCoordinator = PhoneCoordinator(navigationController: navigationController)
35 phoneCoordinator.didEndFlow = { [weak self] in
36 phoneCoordinator.didEndFlow = { [weak self] in
36− self?.launch = LaunchOptions.main // TESTING
37 self?.start()
37 self?.start()
38 self?.removeDependency(phoneCoordinator)
38 self?.removeDependency(phoneCoordinator)
39 }
39 }
@@ -62,8 +62,18 @@ extension ApplicationCoordinator {
62 case auth, admin, main
62 case auth, admin, main
63
63
64 static func configure() -> LaunchOptions {
64 static func configure() -> LaunchOptions {
65− print("configuring...")
65+ let isAuthorized = DataStorage.standard.isLoggedIn()
66+ let isAdmin = DataStorage.standard.getUserModel()?.isAdmin ?? false
67+
68+ if !isAuthorized {
66− return .auth
69+ return .auth
70+ }
71+
72+ if isAdmin {
73+ return .admin
74+ }
75+
76+ return .main
67 }
77 }
68 }
78 }
69}
79}
Hookah Tau/Controllers/Authentication/Code from sms/CodeSmsViewController.swift+1
@@ -91,6 +91,7 @@ final class CodeSmsViewController: AuthorizationViewController {
91 self?.displayAlert(forError: err)
91 self?.displayAlert(forError: err)
92 case .success(let user):
92 case .success(let user):
93 DataStorage.standard.saveUserModel(user)
93 DataStorage.standard.saveUserModel(user)
94+ DataStorage.standard.setLoggedInState(true)
94 self?.coordinator?.goToNextStep()
95 self?.coordinator?.goToNextStep()
95 }
96 }
96 }
97 }
Hookah Tau/Controllers/Authentication/Phone/PhoneCoordinator.swift+7−2
@@ -6,7 +6,7 @@
6// Copyright © 2019 Daria Rednikina. All rights reserved.
6// Copyright © 2019 Daria Rednikina. All rights reserved.
7//
7//
8
8
9−import Foundation
9+import UIKit
10
10
11class PhoneCoordinator: BaseCoordinator {
11class PhoneCoordinator: BaseCoordinator {
12
12
@@ -15,7 +15,12 @@ class PhoneCoordinator: BaseCoordinator {
15 override func start() {
15 override func start() {
16 let phoneVC = PhoneNumberViewController()
16 let phoneVC = PhoneNumberViewController()
17 phoneVC.coordinator = self
17 phoneVC.coordinator = self
18− navigationController?.viewControllers = [ phoneVC ]
18+
19+ let appDelegate = UIApplication.shared.delegate as? AppDelegate
20+ guard let appD = appDelegate else { return }
21+ appD.window?.rootViewController = navigationController
22+
23+ navigationController?.pushViewController(phoneVC, animated: false)
19 }
24 }
20
25
21 /// Method chooses next step. Depends on weather user was previously registered
26 /// Method chooses next step. Depends on weather user was previously registered
Hookah Tau/Controllers/BaseViewController.swift+14−4
@@ -16,7 +16,10 @@ class BaseViewController: UIViewController {
16
16
17 // MARK: - Buttons
17 // MARK: - Buttons
18
18
19− func addStackViewWithButtons(leftBtn: Button? = nil, rightBtn: Button? = nil) {
19+ func addStackViewWithButtons(leftBtn: Button? = nil,
20+ rightBtn: Button? = nil,
21+ constant: CGFloat = -20) {
22+
20 let stackView = UIStackView()
23 let stackView = UIStackView()
21 stackView.translatesAutoresizingMaskIntoConstraints = false
24 stackView.translatesAutoresizingMaskIntoConstraints = false
22 stackView.backgroundColor = .red
25 stackView.backgroundColor = .red
@@ -25,7 +28,14 @@ class BaseViewController: UIViewController {
25 leftBtn?.translatesAutoresizingMaskIntoConstraints = false
28 leftBtn?.translatesAutoresizingMaskIntoConstraints = false
26 rightBtn?.translatesAutoresizingMaskIntoConstraints = false
29 rightBtn?.translatesAutoresizingMaskIntoConstraints = false
27
30
28− bottomConstraint = NSLayoutConstraint(item: stackView, attribute: .bottom, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: -20)
31+ bottomConstraint = NSLayoutConstraint(item: stackView,
32+ attribute: .bottom,
33+ relatedBy: .equal,
34+ toItem: view.safeAreaLayoutGuide,
35+ attribute: .bottom,
36+ multiplier: 1,
37+ constant: constant)
38+
29 guard let bottomContraint = bottomConstraint else { return }
39 guard let bottomContraint = bottomConstraint else { return }
30 view.addConstraint(bottomContraint)
40 view.addConstraint(bottomContraint)
31
41
@@ -100,8 +110,8 @@ class BaseViewController: UIViewController {
100
110
101 // MARK: - Alert
111 // MARK: - Alert
102
112
103− func displayAlert(forError error: GeneralError) {
113+ func displayAlert(forError error: GeneralError = GeneralError.noData, with message: String? = nil) {
104− var title: String? = "MEOW"
114+ var title: String? = message != nil ? error.localizedDescription : message
105 switch error {
115 switch error {
106 case .serverError(let se):
116 case .serverError(let se):
107 title = se.error
117 title = se.error
Hookah Tau/Controllers/Client/Profile/ProfileClientViewController.swift+12−2
@@ -14,8 +14,9 @@ class ProfileClientViewController: UIViewController {
14
14
15 weak var coordinator: ProfileCoordinator?
15 weak var coordinator: ProfileCoordinator?
16
16
17− var model: User = User(name: "Стасик", phoneNumber: "+ 8 901 733 01 79", isAdmin: false) {
17+ var model: User? {
18 didSet {
18 didSet {
19+ guard let model = model else { return }
19 profileContentView?.bind(withModel: model)
20 profileContentView?.bind(withModel: model)
20 }
21 }
21 }
22 }
@@ -33,7 +34,9 @@ class ProfileClientViewController: UIViewController {
33 navigationController?.navigationBar.prefersLargeTitles = true
34 navigationController?.navigationBar.prefersLargeTitles = true
34
35
35 profileContentView = ProfileView.loadFromNib()
36 profileContentView = ProfileView.loadFromNib()
36− profileContentView?.bind(withModel: model)
37+ profileContentView?.logOutButton?.addTarget(self, action: #selector(logout), for: .touchUpInside)
38+
39+ model = DataStorage.standard.getUserModel()
37
40
38 view.addSubviewThatFills(profileContentView)
41 view.addSubviewThatFills(profileContentView)
39
42
@@ -41,19 +44,26 @@ class ProfileClientViewController: UIViewController {
41 }
44 }
42
45
43 @objc func presentChangeViewPhone() {
46 @objc func presentChangeViewPhone() {
47+ guard let model = model else { return }
44 let changeModel = ChangeModel(userModel: model, editingOption: .phone)
48 let changeModel = ChangeModel(userModel: model, editingOption: .phone)
45 coordinator?.presentEditMode(withModel: changeModel)
49 coordinator?.presentEditMode(withModel: changeModel)
46 }
50 }
47
51
48 @objc func presentChangeViewInvite() {
52 @objc func presentChangeViewInvite() {
53+ guard let model = model else { return }
49 let changeModel = ChangeModel(userModel: model, editingOption: .invite)
54 let changeModel = ChangeModel(userModel: model, editingOption: .invite)
50 coordinator?.presentEditMode(withModel: changeModel)
55 coordinator?.presentEditMode(withModel: changeModel)
51 }
56 }
52
57
53 @objc func presentChangeViewName() {
58 @objc func presentChangeViewName() {
59+ guard let model = model else { return }
54 let changeModel = ChangeModel(userModel: model, editingOption: .name)
60 let changeModel = ChangeModel(userModel: model, editingOption: .name)
55 coordinator?.presentEditMode(withModel: changeModel)
61 coordinator?.presentEditMode(withModel: changeModel)
56 }
62 }
63+
64+ @objc func logout() {
65+ coordinator?.logout()
66+ }
57}
67}
58
68
59// MARK: - UserUpdate ext
69// MARK: - UserUpdate ext
Hookah Tau/Controllers/Client/Profile/ProfileCoordinator.swift+2−1
@@ -33,6 +33,7 @@ class ProfileCoordinator: BaseCoordinator {
33 }
33 }
34
34
35 func logout() {
35 func logout() {
36−
36+ DataStorage.standard.setLoggedInState(false)
37+ didEndFlow?()
37 }
38 }
38}
39}
Hookah Tau/Controllers/Client/Reservations/Active Reservations/ReservationsCoordinator.swift+14
@@ -29,4 +29,18 @@ class ReservationsCoordinator: BaseCoordinator {
29 }
29 }
30 addressCoordinator.start()
30 addressCoordinator.start()
31 }
31 }
32+
33+ func viewReservation(_ reservation: Reservation) {
34+ let thirdStepRCoordinator = ThirdStepReservationCoordinator(navigationController: navigationController)
35+ addDependency(thirdStepRCoordinator)
36+
37+ thirdStepRCoordinator.resrvation = reservation
38+
39+ thirdStepRCoordinator.didFinish = { [weak self] in
40+ self?.removeDependency(thirdStepRCoordinator)
41+ self?.navigationController?.popViewController(animated: true)
42+ }
43+
44+ thirdStepRCoordinator.start()
45+ }
32}
46}
Hookah Tau/Controllers/Client/Reservations/Active Reservations/ReservationsViewController.swift+121−19
@@ -10,11 +10,26 @@ import UIKit
10
10
11let reservationCell = "ReservationCell"
11let reservationCell = "ReservationCell"
12
12
13−class ReservationsViewController: UIViewController {
13+class ReservationsViewController: BaseViewController {
14
14
15 // MARK: - Properties
15 // MARK: - Properties
16
16
17− var activeReservations = [1]
17+ var activeReservations: [Reservation] = [] {
18+ didSet {
19+ guard let empty = noReservationsView else { return }
20+ if activeReservations.isEmpty {
21+ contentView.bringSubviewToFront(empty)
22+ empty.alpha = 1
23+ } else {
24+ contentView.sendSubviewToBack(empty)
25+ tableView?.alpha = 1
26+ }
27+
28+ tableView?.reloadData()
29+ }
30+ }
31+
32+ var reservationsService: ReservationsService?
18
33
19 weak var coordinator: ReservationsCoordinator?
34 weak var coordinator: ReservationsCoordinator?
20
35
@@ -26,20 +41,64 @@ class ReservationsViewController: UIViewController {
26
41
27 var noReservationsView: NoReservationsView?
42 var noReservationsView: NoReservationsView?
28
43
29− var tableView: UITableView?
44+ var tableView: UITableView? = {
45+ let tableView = UITableView()
46+ tableView.backgroundColor = .white
47+ return tableView
48+ }()
30
49
31 // MARK: - Lifecycle
50 // MARK: - Lifecycle
32
51
33 override func viewDidLoad() {
52 override func viewDidLoad() {
34 super.viewDidLoad()
53 super.viewDidLoad()
35
54
55+ setUpNavigationBar()
56+
57+ reservationsService = ReservationsService(apiClient: APIClient.shared)
58+ navigationController?.navigationBar.prefersLargeTitles = true
36 setUpContentView()
59 setUpContentView()
60+ }
61+
62+ override func viewWillAppear(_ animated: Bool) {
63+ super.viewWillAppear(animated)
64+
65+ tabBarController?.tabBar.isHidden = false
66+ }
67+
68+ override func viewDidAppear(_ animated: Bool) {
69+ super.viewDidAppear(animated)
70+
71+ performUpdate()
72+ }
73+
74+ // MARK: - Setup
75+
76+ func setUpContentView() {
77+ self.view.addSubviewThatFills(contentView)
37
78
79+ // empty
80+ noReservationsView = NoReservationsView.loadFromNib()
81+ contentView.addSubviewThatFills(noReservationsView)
82+ noReservationsView?.makeReservationButton?.addTarget(self, action: #selector(tapToMakeReservation), for: .touchUpInside)
83+
84+ noReservationsView?.alpha = 0
85+
86+ // table
87+ contentView.addSubviewThatFills(tableView)
88+
89+ setUpTableView()
90+ }
91+
92+ func setUpTableView() {
38 tableView?.delegate = self
93 tableView?.delegate = self
39 tableView?.dataSource = self
94 tableView?.dataSource = self
40
95
96+ tableView?.alpha = 0
97+
41 tableView?.register(ReservationCell.self, forCellReuseIdentifier: reservationCell)
98 tableView?.register(ReservationCell.self, forCellReuseIdentifier: reservationCell)
42−
99+ }
100+
101+ func setUpNavigationBar() {
43 view.backgroundColor = .white
102 view.backgroundColor = .white
44 navigationItem.title = "Брони"
103 navigationItem.title = "Брони"
45
104
@@ -47,27 +106,37 @@ class ReservationsViewController: UIViewController {
47 UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(tapToMakeReservation))
106 UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(tapToMakeReservation))
48 }
107 }
49
108
50− // MARK: - Setup
51−
52− func setUpContentView() {
53− self.view.addSubviewThatFills(contentView)
54−
55− if activeReservations.isEmpty {
56− noReservationsView = NoReservationsView.loadFromNib()
57− contentView.addSubviewThatFills(noReservationsView)
58− noReservationsView?.makeReservationButton?.addTarget(self, action: #selector(tapToMakeReservation), for: .touchUpInside)
59− } else {
60− tableView = UITableView()
61− contentView.addSubviewThatFills(tableView)
62− }
63− }
64−
65 // MARK: - handlers
109 // MARK: - handlers
66
110
67 @objc func tapToMakeReservation() {
111 @objc func tapToMakeReservation() {
68 coordinator?.makeReservation()
112 coordinator?.makeReservation()
69 }
113 }
70
114
115+ // MARK: - Update
116+
117+ func performUpdate() {
118+ reservationsService?.loadUsersReservations(completion: { [weak self] (result) in
119+ switch result {
120+ case .success(let reservations):
121+ self?.activeReservations = reservations
122+ case .failure(let err):
123+ self?.displayAlert(forError: err)
124+ }
125+ })
126+ }
127+
128+ func deleteReservation(uuid: String, completion: @escaping (([Reservation]?) -> Void)) {
129+ reservationsService?.deleteReservation(uuid: uuid) { result in
130+ if result {
131+ let newReservations = self.activeReservations.filter { $0.uuid != uuid }
132+ completion(newReservations)
133+ return
134+ }
135+
136+ completion(nil)
137+ }
138+ }
139+
71}
140}
72
141
73extension ReservationsViewController: UITableViewDelegate, UITableViewDataSource {
142extension ReservationsViewController: UITableViewDelegate, UITableViewDataSource {
@@ -82,6 +151,11 @@ extension ReservationsViewController: UITableViewDelegate, UITableViewDataSource
82 return cell
151 return cell
83 }
152 }
84
153
154+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
155+ let reservation = activeReservations[indexPath.row]
156+ coordinator?.viewReservation(reservation)
157+ }
158+
85 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
159 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
86 return UITableView.automaticDimension
160 return UITableView.automaticDimension
87 }
161 }
@@ -89,4 +163,32 @@ extension ReservationsViewController: UITableViewDelegate, UITableViewDataSource
89 func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
163 func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
90 return 180.0
164 return 180.0
91 }
165 }
166+
167+ // Update
168+
169+ func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
170+ return true
171+ }
172+
173+ func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
174+
175+ let uuid = activeReservations[indexPath.row].uuid
176+ let cancelButton = UITableViewRowAction(style: .normal, title: "❌") { _,_ in
177+
178+ self.deleteReservation(uuid: uuid) { optionalNewVal in
179+ if let newval = optionalNewVal {
180+ self.tableView?.beginUpdates()
181+ self.tableView?.deleteRows(at: [indexPath], with: .automatic)
182+ self.activeReservations = newval
183+ self.tableView?.endUpdates()
184+ } else {
185+ self.displayAlert(with: "Не удалось удалить вашу бронь! Попробуйте еще раз!")
186+ }
187+ }
188+ }
189+
190+ cancelButton.backgroundColor = .black
191+
192+ return [cancelButton]
193+ }
92}
194}
Hookah Tau/Controllers/Client/Reservations/Adress of reservation/AddresViewController.swift+42−1
@@ -16,7 +16,7 @@ class AddresViewController: BaseViewController {
16
16
17 var tableView: UITableView?
17 var tableView: UITableView?
18
18
19− var dataSource: [Int]? = [1]
19+ var dataSource: [Int]? = [1, 2]
20
20
21 // MARK: - Lifecycle
21 // MARK: - Lifecycle
22
22
@@ -24,9 +24,16 @@ class AddresViewController: BaseViewController {
24 view.backgroundColor = .white
24 view.backgroundColor = .white
25 navigationItem.title = "Заведения"
25 navigationItem.title = "Заведения"
26
26
27+ navigationController?.navigationBar.prefersLargeTitles = true
27 setUpTableView()
28 setUpTableView()
28 }
29 }
29
30
31+ override func viewWillAppear(_ animated: Bool) {
32+ super.viewWillAppear(animated)
33+
34+ tabBarController?.tabBar.isHidden = false
35+ }
36+
30 // MARK: - Setup
37 // MARK: - Setup
31
38
32 func setUpTableView() {
39 func setUpTableView() {
@@ -53,6 +60,13 @@ extension AddresViewController: UITableViewDelegate, UITableViewDataSource {
53 let cell = tableView.dequeueReusableCell(withIdentifier: addressCellIdentifier,
60 let cell = tableView.dequeueReusableCell(withIdentifier: addressCellIdentifier,
54 for: indexPath) as! AddressCell
61 for: indexPath) as! AddressCell
55
62
63+ guard
64+ let val = dataSource?[indexPath.row],
65+ let model = TotalStorage.standard.getEstablishment(val)
66+ else { return cell }
67+
68+ cell.bind(withModel: model)
69+
56 return cell
70 return cell
57 }
71 }
58
72
@@ -60,4 +74,31 @@ extension AddresViewController: UITableViewDelegate, UITableViewDataSource {
60 return 168.0
74 return 168.0
61 }
75 }
62
76
77+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
78+ let establishment = dataSource?[indexPath.row]
79+ guard let id = establishment else { return }
80+
81+ coordinator?.chooseTableAndTime(inEstablishment: id)
82+ }
83+
84+ func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
85+ return true
86+ }
87+
88+ func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
89+
90+ guard
91+ let val = dataSource?[indexPath.row],
92+ let phone = TotalStorage.standard.getEstablishment(val)?.admin,
93+ let urlPhone = URL(string: "tel://79\(phone)")
94+ else { return nil }
95+
96+ let editButton = UITableViewRowAction(style: .normal, title: "🤙🏻") { _,_ in
97+ UIApplication.shared.open(urlPhone)
98+ }
99+
100+ editButton.backgroundColor = .black
101+
102+ return [editButton]
103+ }
63}
104}
Hookah Tau/Controllers/Client/Reservations/Adress of reservation/AddressCoordinator.swift+11−1
@@ -29,7 +29,17 @@ class AddressCoordinator: BaseCoordinator {
29
29
30 /// continue with reservation
30 /// continue with reservation
31 /// TODO: pass some data
31 /// TODO: pass some data
32− func chooseTableAndTime() {
32+ func chooseTableAndTime(inEstablishment id: Int) {
33+ let reservationCoordinator = FirstStepReservationCoordinator(navigationController: navigationController)
34+ reservationCoordinator.establishment = id
33
35
36+ addDependency(reservationCoordinator)
37+ reservationCoordinator.didFinish = { [weak self] in
38+ self?.removeDependency(reservationCoordinator)
39+ self?.navigationController?.popViewController(animated: false)
40+ self?.didFinish?()
41+ }
42+
43+ reservationCoordinator.start()
34 }
44 }
35}
45}
Hookah Tau/Controllers/Client/Reservations/Cells/Address/AddressCell.swift+4
@@ -27,6 +27,10 @@ class AddressCell: UITableViewCell {
27
27
28 selectionStyle = .none
28 selectionStyle = .none
29 }
29 }
30+
31+ func bind(withModel model: TotalStorage.EstablishmentData) {
32+ addressView?.bind(withModel: model)
33+ }
30
34
31 required init?(coder aDecoder: NSCoder)
35 required init?(coder aDecoder: NSCoder)
32 {
36 {
Hookah Tau/Controllers/Client/Reservations/Cells/Address/AddressView.swift+6−2
@@ -18,8 +18,12 @@ class AddressView: UIView {
18
18
19 @IBOutlet weak var tableCountLabel: UILabel?
19 @IBOutlet weak var tableCountLabel: UILabel?
20
20
21− @IBOutlet weak var callAdminButton: UIButton?
22−
23 @IBOutlet weak var mapImageView: UIImageView?
21 @IBOutlet weak var mapImageView: UIImageView?
24
22
23+ func bind(withModel model: TotalStorage.EstablishmentData) {
24+ addressLabel?.text = model.address
25+ tableCountLabel?.text = "\(model.maxTableNumber) столов"
26+ mapImageView?.image = model.image
27+ }
28+
25}
29}
Hookah Tau/Controllers/Client/Reservations/Cells/Address/AddressView.xib+28−26
@@ -15,42 +15,45 @@
15 <rect key="frame" x="0.0" y="0.0" width="375" height="168"/>
15 <rect key="frame" x="0.0" y="0.0" width="375" height="168"/>
16 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
16 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
17 <subviews>
17 <subviews>
18− <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="CqA-Dd-eAx">
18+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="top" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="CqA-Dd-eAx">
19 <rect key="frame" x="16" y="16" width="343" height="136"/>
19 <rect key="frame" x="16" y="16" width="343" height="136"/>
20 <subviews>
20 <subviews>
21− <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="bottom" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="wiw-lV-dNd">
21+ <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="VqZ-I8-mm0">
22− <rect key="frame" x="0.0" y="16" width="164.5" height="104.5"/>
22+ <rect key="frame" x="0.0" y="0.0" width="200" height="136"/>
23 <subviews>
23 <subviews>
24− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Покровский, 11" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9py-8w-XFJ">
25− <rect key="frame" x="0.0" y="0.0" width="164.5" height="26.5"/>
26− <fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
27− <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
28− <nil key="highlightedColor"/>
29− </label>
30− <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="bottom" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="lyA-et-Gg5">
24+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="bottom" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="wiw-lV-dNd">
31− <rect key="frame" x="54" y="56.5" width="110.5" height="48"/>
25+ <rect key="frame" x="0.0" y="0.0" width="200" height="136"/>
32 <subviews>
26 <subviews>
33− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3:00 — 12:00" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SrE-GD-vqp">
27+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Гороховский пер. 12c5, апт. 205" textAlignment="right" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9py-8w-XFJ">
34− <rect key="frame" x="0.0" y="0.0" width="110.5" height="20.5"/>
28+ <rect key="frame" x="7" y="0.0" width="193" height="53"/>
35− <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
29+ <fontDescription key="fontDescription" type="boldSystem" pointSize="22"/>
36 <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
30 <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
37 <nil key="highlightedColor"/>
31 <nil key="highlightedColor"/>
38 </label>
32 </label>
33+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="bottom" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="lyA-et-Gg5">
34+ <rect key="frame" x="89.5" y="88" width="110.5" height="48"/>
35+ <subviews>
36+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3:00 — 12:00" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SrE-GD-vqp">
37+ <rect key="frame" x="0.0" y="0.0" width="110.5" height="20.5"/>
38+ <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
39+ <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
40+ <nil key="highlightedColor"/>
41+ </label>
39− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="8 столов" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9nc-mT-R6o">
42+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="8 столов" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9nc-mT-R6o">
40− <rect key="frame" x="44.5" y="28.5" width="66" height="19.5"/>
43+ <rect key="frame" x="44.5" y="28.5" width="66" height="19.5"/>
41− <fontDescription key="fontDescription" type="system" pointSize="16"/>
44+ <fontDescription key="fontDescription" type="system" pointSize="16"/>
42− <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
45+ <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
43− <nil key="highlightedColor"/>
46+ <nil key="highlightedColor"/>
44− </label>
47+ </label>
48+ </subviews>
49+ </stackView>
45 </subviews>
50 </subviews>
51+ <constraints>
52+ <constraint firstAttribute="width" constant="200" id="Lgy-TT-MRN"/>
53+ </constraints>
46 </stackView>
54 </stackView>
47 </subviews>
55 </subviews>
48 </stackView>
56 </stackView>
49− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GTd-he-e50">
50− <rect key="frame" x="227" y="53" width="116" height="30"/>
51− <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
52− <state key="normal" title="Большая кнопка"/>
53− </button>
54 </subviews>
57 </subviews>
55 </stackView>
58 </stackView>
56 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Map" translatesAutoresizingMaskIntoConstraints="NO" id="2Oj-R4-qoR">
59 <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Map" translatesAutoresizingMaskIntoConstraints="NO" id="2Oj-R4-qoR">
@@ -75,7 +78,6 @@
75 <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
78 <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
76 <connections>
79 <connections>
77 <outlet property="addressLabel" destination="9py-8w-XFJ" id="RzN-vT-9co"/>
80 <outlet property="addressLabel" destination="9py-8w-XFJ" id="RzN-vT-9co"/>
78− <outlet property="callAdminButton" destination="GTd-he-e50" id="bdq-pP-al5"/>
79 <outlet property="mapImageView" destination="2Oj-R4-qoR" id="3ao-l1-GTd"/>
81 <outlet property="mapImageView" destination="2Oj-R4-qoR" id="3ao-l1-GTd"/>
80 <outlet property="openHoursLabel" destination="SrE-GD-vqp" id="gAb-rI-1wP"/>
82 <outlet property="openHoursLabel" destination="SrE-GD-vqp" id="gAb-rI-1wP"/>
81 <outlet property="tableCountLabel" destination="9nc-mT-R6o" id="tlM-MK-qTx"/>
83 <outlet property="tableCountLabel" destination="9nc-mT-R6o" id="tlM-MK-qTx"/>
Hookah Tau/Controllers/Client/Reservations/Cells/Reservation/ReservationCell.swift+2−3
@@ -33,8 +33,7 @@ class ReservationCell: UITableViewCell {
33
33
34 // MARK: - Data
34 // MARK: - Data
35
35
36− func bind(withModel model: Int) {
36+ func bind(withModel model: Reservation) {
37−
37+ reservationCellView?.bind(withModel: model)
38 }
38 }
39−
40}
39}
Hookah Tau/Controllers/Client/Reservations/Cells/Reservation/ReservationView.swift+11−61
@@ -21,68 +21,18 @@ class ReservationView: UIView {
21 @IBOutlet weak var maxPeopleLabel: UILabel?
21 @IBOutlet weak var maxPeopleLabel: UILabel?
22
22
23 @IBOutlet weak var tableImageView: UIImageView?
23 @IBOutlet weak var tableImageView: UIImageView?
24−
25− @IBOutlet weak var cancelButton: Button? {
26− didSet {
27− let style = BlackButtonStyle()
28− style.apply(to: cancelButton, withTitle: "ОТМЕНИТЬ")
29− }
30− }
31−
32− @IBOutlet weak var changeButton: Button? {
33− didSet {
34− let style = BlackButtonStyle()
35− style.apply(to: changeButton, withTitle: "ИЗМЕНИТЬ")
36− }
37− }
38−
39− @IBOutlet weak var swipableView: UIView?
40−
41−
42− override func awakeFromNib() {
43− super.awakeFromNib()
44−
45− }
46−
47− // https://developer.apple.com/videos/play/wwdc2015/229/
48− @IBAction func swipeImageView(_ recognizer: UIPanGestureRecognizer) {
49− let translation = recognizer.translation(in: self.swipableView)
50− guard let view = recognizer.view else { return }
51−
52− let point = CGPoint(x: view.center.x + translation.x, y: view.center.y)
53− if self.swipableView?.bounds.contains(point) == true {
54− view.center = point
55− }
56−
57− recognizer.setTranslation(CGPoint.zero, in: self.swipableView)
58−
59− if recognizer.state == .ended {
60− // 1
61− let velocity = recognizer.velocity(in: self.swipableView)
62− let magnitude = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y))
63− let slideMultiplier = magnitude / 300
64− print("magnitude: \(magnitude), slideMultiplier: \(slideMultiplier)")
65−
66− // 2
67− let slideFactor = 0.1 * slideMultiplier //Increase for more of a slide
68− // 3
69− var finalPoint = CGPoint(x:view.center.x + (velocity.x * slideFactor),
70− y:view.center.y)
71− // 4
72− finalPoint.x = min(max(finalPoint.x, 0), self.swipableView?.bounds.size.width ?? 0.0 - view.bounds.width / 2 )
73
24
74− // 5
25+ func bind(withModel model: Reservation) {
75− UIView.animate(withDuration: Double(slideFactor * 2),
26+ guard let table = TotalStorage.standard.getTable(establishment: model.establishment, table: model.reservedTable),
76− delay: 0,
27+ let establishment = TotalStorage.standard.getEstablishment(model.establishment)
77− // 6
28+ else { return }
78− options: UIView.AnimationOptions.curveEaseOut,
79− animations: { view.center = finalPoint },
80− completion: nil)
81− }
82− }
83−
84− private func checkArea(_ coord: CGPoint) {
85
29
30+ tableImageView?.image = table.image
31+ adressLabel?.text = establishment.address
32+ maxPeopleLabel?.text = "\(model.numberOfGuests) " + (2...4 ~= model.numberOfGuests ? "человека" : "человек")
33+
34+ let (date, time) = Date.format(model.startTime, model.endTime)
35+ dateLabel?.text = date
36+ timeLabel?.text = time
86 }
37 }
87−
88}
38}
Hookah Tau/Controllers/Client/Reservations/Cells/Reservation/ReservationView.xib+7−55
@@ -16,12 +16,12 @@
16 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
16 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
17 <subviews>
17 <subviews>
18 <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="gQe-LE-1cq">
18 <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="gQe-LE-1cq">
19− <rect key="frame" x="20" y="22" width="374" height="136"/>
19+ <rect key="frame" x="20" y="20" width="374" height="140"/>
20 <subviews>
20 <subviews>
21 <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="25" translatesAutoresizingMaskIntoConstraints="NO" id="Ujo-xw-Sa3">
21 <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="25" translatesAutoresizingMaskIntoConstraints="NO" id="Ujo-xw-Sa3">
22− <rect key="frame" x="0.0" y="0.0" width="256" height="136"/>
22+ <rect key="frame" x="0.0" y="2" width="243" height="136"/>
23 <subviews>
23 <subviews>
24− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Покровский, 11" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QIM-G6-tcZ">
24+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Покровский, 11" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QIM-G6-tcZ">
25 <rect key="frame" x="0.0" y="0.0" width="122" height="20.5"/>
25 <rect key="frame" x="0.0" y="0.0" width="122" height="20.5"/>
26 <fontDescription key="fontDescription" type="system" pointSize="17"/>
26 <fontDescription key="fontDescription" type="system" pointSize="17"/>
27 <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
27 <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -52,36 +52,8 @@
52 </label>
52 </label>
53 </subviews>
53 </subviews>
54 </stackView>
54 </stackView>
55− <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="KIf-G6-yu0">
56− <rect key="frame" x="264" y="24" width="110" height="88"/>
57− <subviews>
58− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7Kd-Rw-JdQ" customClass="Button" customModule="Hookah_Tau" customModuleProvider="target">
59− <rect key="frame" x="0.0" y="0.0" width="110" height="35"/>
60− <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
61− <constraints>
62− <constraint firstAttribute="width" constant="110" id="db3-Z9-qoz"/>
63− <constraint firstAttribute="height" constant="35" id="fvx-DS-94n"/>
64− </constraints>
65− <state key="normal" title="Отменить"/>
66− </button>
67− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="L1q-Xa-K3y" customClass="Button" customModule="Hookah_Tau" customModuleProvider="target">
68− <rect key="frame" x="0.0" y="53" width="110" height="35"/>
69− <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
70− <constraints>
71− <constraint firstAttribute="height" constant="35" id="29E-JH-Mv8"/>
72− <constraint firstAttribute="width" constant="110" id="UCh-du-cnE"/>
73− </constraints>
74− <state key="normal" title="Изменить"/>
75− </button>
76− </subviews>
77− </stackView>
78− </subviews>
79− </stackView>
80− <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="m4Q-p5-icZ">
81− <rect key="frame" x="144" y="0.0" width="250" height="180"/>
82− <subviews>
83 <imageView clipsSubviews="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Table" translatesAutoresizingMaskIntoConstraints="NO" id="4u1-cy-ujz">
55 <imageView clipsSubviews="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Table" translatesAutoresizingMaskIntoConstraints="NO" id="4u1-cy-ujz">
84− <rect key="frame" x="127" y="20" width="123" height="140"/>
56+ <rect key="frame" x="251" y="0.0" width="123" height="140"/>
85 <gestureRecognizers/>
57 <gestureRecognizers/>
86 <constraints>
58 <constraints>
87 <constraint firstAttribute="width" constant="123" id="3ZG-yo-kHP"/>
59 <constraint firstAttribute="width" constant="123" id="3ZG-yo-kHP"/>
@@ -89,50 +61,30 @@
89 <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="123" id="weI-IM-eIN"/>
61 <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="123" id="weI-IM-eIN"/>
90 <constraint firstAttribute="height" constant="140" id="xVK-aV-obb"/>
62 <constraint firstAttribute="height" constant="140" id="xVK-aV-obb"/>
91 </constraints>
63 </constraints>
92− <connections>
93− <outletCollection property="gestureRecognizers" destination="PRF-YF-b6m" appends="YES" id="DjN-h4-Tdp"/>
94− </connections>
95 </imageView>
64 </imageView>
96 </subviews>
65 </subviews>
97− <color key="backgroundColor" red="0.012039811643835616" green="0.56175085616438358" blue="0.76225385273972601" alpha="0.2090378852739726" colorSpace="custom" customColorSpace="sRGB"/>
66+ </stackView>
98− <constraints>
99− <constraint firstItem="4u1-cy-ujz" firstAttribute="top" secondItem="m4Q-p5-icZ" secondAttribute="top" constant="20" id="E3a-gf-bth"/>
100− <constraint firstAttribute="width" constant="250" id="JQc-Wc-jc0"/>
101− <constraint firstAttribute="trailing" secondItem="4u1-cy-ujz" secondAttribute="trailing" id="JfQ-6n-41A"/>
102− <constraint firstAttribute="bottom" secondItem="4u1-cy-ujz" secondAttribute="bottom" constant="20" id="gNA-cS-SKe"/>
103− <constraint firstAttribute="height" constant="180" id="uWH-MW-jqV"/>
104− </constraints>
105− </view>
106 </subviews>
67 </subviews>
107 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
68 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
108 <constraints>
69 <constraints>
109 <constraint firstItem="gQe-LE-1cq" firstAttribute="centerY" secondItem="vUN-kp-3ea" secondAttribute="centerY" id="0yM-pg-c5m"/>
70 <constraint firstItem="gQe-LE-1cq" firstAttribute="centerY" secondItem="vUN-kp-3ea" secondAttribute="centerY" id="0yM-pg-c5m"/>
110− <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="m4Q-p5-icZ" secondAttribute="trailing" constant="20" id="8aC-G7-xGp"/>
71+ <constraint firstItem="gQe-LE-1cq" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="20" id="TQU-8e-jES"/>
111− <constraint firstItem="m4Q-p5-icZ" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="D3I-d9-a60"/>
112 <constraint firstItem="gQe-LE-1cq" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="guw-kE-R18"/>
72 <constraint firstItem="gQe-LE-1cq" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="guw-kE-R18"/>
73+ <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="gQe-LE-1cq" secondAttribute="bottom" constant="20" id="pgS-KL-ECQ"/>
113 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="gQe-LE-1cq" secondAttribute="trailing" constant="20" id="rw9-VV-8S5"/>
74 <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="gQe-LE-1cq" secondAttribute="trailing" constant="20" id="rw9-VV-8S5"/>
114 <constraint firstItem="gQe-LE-1cq" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="vQj-YK-exg"/>
75 <constraint firstItem="gQe-LE-1cq" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="vQj-YK-exg"/>
115− <constraint firstItem="m4Q-p5-icZ" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="yMN-Gy-814"/>
116 </constraints>
76 </constraints>
117 <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
77 <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
118 <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
78 <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
119 <connections>
79 <connections>
120 <outlet property="adressLabel" destination="QIM-G6-tcZ" id="bRM-hB-jwH"/>
80 <outlet property="adressLabel" destination="QIM-G6-tcZ" id="bRM-hB-jwH"/>
121− <outlet property="cancelButton" destination="7Kd-Rw-JdQ" id="3wP-jU-Vlz"/>
122− <outlet property="changeButton" destination="L1q-Xa-K3y" id="Uot-1g-x9O"/>
123 <outlet property="dateLabel" destination="lUJ-we-26h" id="cMr-gz-ofj"/>
81 <outlet property="dateLabel" destination="lUJ-we-26h" id="cMr-gz-ofj"/>
124 <outlet property="maxPeopleLabel" destination="fYQ-YQ-Bw4" id="Utn-Bd-dVK"/>
82 <outlet property="maxPeopleLabel" destination="fYQ-YQ-Bw4" id="Utn-Bd-dVK"/>
125− <outlet property="swipableView" destination="m4Q-p5-icZ" id="1gn-M1-Lfg"/>
126 <outlet property="tableImageView" destination="4u1-cy-ujz" id="d1Z-TE-u1y"/>
83 <outlet property="tableImageView" destination="4u1-cy-ujz" id="d1Z-TE-u1y"/>
127 <outlet property="timeLabel" destination="EOi-j1-jQM" id="CV4-G4-wUw"/>
84 <outlet property="timeLabel" destination="EOi-j1-jQM" id="CV4-G4-wUw"/>
128 </connections>
85 </connections>
129 <point key="canvasLocation" x="165" y="350"/>
86 <point key="canvasLocation" x="165" y="350"/>
130 </view>
87 </view>
131− <panGestureRecognizer minimumNumberOfTouches="1" id="PRF-YF-b6m">
132− <connections>
133− <action selector="swipeImageView:" destination="iN0-l3-epB" id="zIb-fN-SWJ"/>
134− </connections>
135− </panGestureRecognizer>
136 </objects>
88 </objects>
137 <resources>
89 <resources>
138 <image name="Table" width="102" height="117"/>
90 <image name="Table" width="102" height="117"/>
Hookah Tau/Controllers/Client/Reservations/Maps/1/MapView1.swiftnew file+170
@@ -0,0 +1,170 @@
1+//
2+// MapView1.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 06/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+protocol MapHandler: class {
12+ func handleTap(withId id: Int)
13+}
14+
15+class MapView1: MapImageScroll, UIScrollViewDelegate {
16+
17+ // MARK: - Properties
18+
19+ @IBOutlet weak var shadow: UIView! {
20+ didSet {
21+ super.shadowView = shadow
22+ shadow.alpha = 0
23+ }
24+ }
25+
26+ override var handler: MapHandler? {
27+ didSet {
28+ handleTap(button: firstTable, id: 1)
29+ }
30+ }
31+
32+
33+ @IBOutlet weak var scrollView: UIScrollView! {
34+ didSet {
35+ super.scrollViewParent = scrollView
36+ }
37+ }
38+
39+ @IBOutlet weak var image: UIImageView! {
40+ didSet {
41+ super.img = image
42+ }
43+ }
44+
45+ @IBOutlet weak var firstTable: TableButton! {
46+ didSet {
47+ let style = TableButtonStyle()
48+ style.apply(to: firstTable)
49+ firstTable.transform = CGAffineTransform(rotationAngle: CGFloat(-Double.pi / 4));
50+ }
51+ }
52+
53+
54+ @IBOutlet weak var secondTable: TableButton! {
55+ didSet {
56+ let style = TableButtonStyle()
57+ style.apply(to: secondTable)
58+ }
59+ }
60+
61+ @IBOutlet weak var trirdTable: TableButton! {
62+ didSet {
63+ let style = TableButtonStyle()
64+ style.apply(to: trirdTable)
65+ }
66+ }
67+
68+ @IBOutlet weak var forthTable: TableButton! {
69+ didSet {
70+ let style = TableButtonStyle()
71+ style.apply(to: forthTable)
72+ }
73+ }
74+
75+ @IBOutlet weak var fifthTable: TableButton! {
76+ didSet {
77+ let style = TableButtonStyle()
78+ style.apply(to: fifthTable)
79+ }
80+ }
81+
82+ @IBOutlet weak var sixthTable: TableButton! {
83+ didSet {
84+ let style = TableButtonStyle()
85+ style.apply(to: sixthTable)
86+ }
87+ }
88+
89+ @IBOutlet weak var seventhTable: TableButton! {
90+ didSet {
91+ let style = TableButtonStyle()
92+ style.apply(to: seventhTable)
93+ }
94+ }
95+
96+ @IBOutlet weak var eighthTable: TableButton! {
97+ didSet {
98+ let style = TableButtonStyle()
99+ style.apply(to: eighthTable)
100+ }
101+ }
102+
103+ // MARK: - Lifecycle
104+
105+ override func awakeFromNib() {
106+ super.awakeFromNib()
107+
108+ self.scrollView.delegate = self
109+ self.scrollView.delaysContentTouches = false
110+
111+ image.addSubview(shadow)
112+ image.addSubview(firstTable)
113+ image.addSubview(secondTable)
114+ image.addSubview(trirdTable)
115+ image.addSubview(forthTable)
116+ image.addSubview(fifthTable)
117+ image.addSubview(sixthTable)
118+ image.addSubview(seventhTable)
119+ image.addSubview(eighthTable)
120+
121+ tables[1] = firstTable
122+ tables[2] = secondTable
123+ tables[3] = trirdTable
124+ tables[4] = forthTable
125+ tables[5] = fifthTable
126+ tables[6] = sixthTable
127+ tables[7] = seventhTable
128+ tables[8] = eighthTable
129+
130+ configureFor(image.frame.size)
131+ }
132+
133+ @IBAction func chooseSecondTable(_ sender: TableButton) {
134+ handleTap(button: sender, id: 2)
135+ }
136+
137+ @IBAction func chooseFifthTable(_ sender: TableButton) {
138+ handleTap(button: sender, id: 5)
139+ }
140+
141+ @IBAction func choseSeventhTable(_ sender: TableButton) {
142+ handleTap(button: sender, id: 7)
143+ }
144+
145+ @IBAction func chooseFirstTable(_ sender: TableButton) {
146+ handleTap(button: sender, id: 1)
147+ }
148+
149+ @IBAction func chooseThirdTable(_ sender: TableButton) {
150+ handleTap(button: sender, id: 3)
151+ }
152+
153+ @IBAction func choose4thTable(_ sender: TableButton) {
154+ handleTap(button: sender, id: 4)
155+ }
156+
157+ @IBAction func choose6thTable(_ sender: TableButton) {
158+ handleTap(button: sender, id: 6)
159+ }
160+
161+ @IBAction func choose8thTable(_ sender: TableButton) {
162+ handleTap(button: sender, id: 8)
163+ }
164+
165+ // MARK: - Scroll view
166+
167+ func viewForZooming(in scrollView: UIScrollView) -> UIView? {
168+ self.image
169+ }
170+}
Hookah Tau/Controllers/Client/Reservations/Maps/1/MapView1.xibnew file+175
@@ -0,0 +1,175 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina4_7" orientation="portrait" appearance="light"/>
4+ <dependencies>
5+ <deployment identifier="iOS"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9+ </dependencies>
10+ <objects>
11+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
12+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
13+ <view clipsSubviews="YES" contentMode="scaleToFill" id="iN0-l3-epB" customClass="MapView1" customModule="Hookah_Tau" customModuleProvider="target">
14+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
15+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
16+ <subviews>
17+ <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FuE-LV-NBR">
18+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
19+ <subviews>
20+ <imageView clipsSubviews="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="map_1" translatesAutoresizingMaskIntoConstraints="NO" id="btD-Wl-3P6">
21+ <rect key="frame" x="0.0" y="0.0" width="536" height="636"/>
22+ </imageView>
23+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Y23-Wu-4BW" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
24+ <rect key="frame" x="44" y="37" width="102" height="117"/>
25+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
26+ <constraints>
27+ <constraint firstAttribute="width" constant="102" id="EKZ-Ny-4RQ"/>
28+ <constraint firstAttribute="height" constant="117" id="u1N-5d-cFR"/>
29+ </constraints>
30+ <connections>
31+ <action selector="chooseFirstTable:" destination="iN0-l3-epB" eventType="touchUpInside" id="1O9-7Q-a8g"/>
32+ </connections>
33+ </button>
34+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xsw-fJ-8cN" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
35+ <rect key="frame" x="209" y="113" width="131" height="119"/>
36+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
37+ <constraints>
38+ <constraint firstAttribute="width" constant="131" id="2xi-Oz-ceC"/>
39+ <constraint firstAttribute="height" constant="119" id="xPD-fh-9Zg"/>
40+ </constraints>
41+ <connections>
42+ <action selector="chooseSecondTable:" destination="iN0-l3-epB" eventType="touchUpInside" id="5XE-gZ-DyJ"/>
43+ </connections>
44+ </button>
45+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="onR-hl-Q2x" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
46+ <rect key="frame" x="60" y="213" width="102" height="119"/>
47+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
48+ <constraints>
49+ <constraint firstAttribute="height" constant="119" id="JWf-x8-7CB"/>
50+ <constraint firstAttribute="width" constant="102" id="LZN-1O-mIP"/>
51+ </constraints>
52+ <connections>
53+ <action selector="choose6thTable:" destination="iN0-l3-epB" eventType="touchUpInside" id="gA4-cd-CZo"/>
54+ </connections>
55+ </button>
56+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Fw9-l6-N8a" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
57+ <rect key="frame" x="60" y="350" width="102" height="118"/>
58+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
59+ <constraints>
60+ <constraint firstAttribute="height" constant="118" id="2Vp-Ip-7cO"/>
61+ <constraint firstAttribute="width" constant="102" id="2hI-75-UCM"/>
62+ </constraints>
63+ <connections>
64+ <action selector="choseSeventhTable:" destination="iN0-l3-epB" eventType="touchUpInside" id="94e-DE-SAJ"/>
65+ </connections>
66+ </button>
67+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KJZ-Nl-7hH" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
68+ <rect key="frame" x="222" y="272" width="104" height="119"/>
69+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
70+ <constraints>
71+ <constraint firstAttribute="height" constant="119" id="Ifu-kd-YHH"/>
72+ <constraint firstAttribute="width" constant="104" id="phm-aP-6dx"/>
73+ </constraints>
74+ <connections>
75+ <action selector="chooseFifthTable:" destination="iN0-l3-epB" eventType="touchUpInside" id="Tc2-ir-tPU"/>
76+ </connections>
77+ </button>
78+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mUw-im-1BC" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
79+ <rect key="frame" x="222" y="431" width="92" height="67"/>
80+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
81+ <constraints>
82+ <constraint firstAttribute="width" constant="92" id="AJ6-ku-4R3"/>
83+ <constraint firstAttribute="height" constant="67" id="jVI-uI-YDT"/>
84+ </constraints>
85+ <connections>
86+ <action selector="choose8thTable:" destination="iN0-l3-epB" eventType="touchUpInside" id="C8U-7T-Bsc"/>
87+ </connections>
88+ </button>
89+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aIM-Qn-Uhl" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
90+ <rect key="frame" x="386" y="116" width="130" height="119"/>
91+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
92+ <constraints>
93+ <constraint firstAttribute="width" constant="130" id="Lhq-jM-PQ0"/>
94+ <constraint firstAttribute="height" constant="119" id="vsx-u8-L6o"/>
95+ </constraints>
96+ <connections>
97+ <action selector="chooseThirdTable:" destination="iN0-l3-epB" eventType="touchUpInside" id="eQS-Wo-hTf"/>
98+ </connections>
99+ </button>
100+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wpi-6E-c5p" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
101+ <rect key="frame" x="399" y="275" width="104" height="119"/>
102+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
103+ <constraints>
104+ <constraint firstAttribute="height" constant="119" id="Lib-3b-h8b"/>
105+ <constraint firstAttribute="width" constant="104" id="nch-5L-cRo"/>
106+ </constraints>
107+ <connections>
108+ <action selector="choose4thTable:" destination="iN0-l3-epB" eventType="touchUpInside" id="U5p-In-FEa"/>
109+ </connections>
110+ </button>
111+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zbE-1g-Qz4">
112+ <rect key="frame" x="0.0" y="0.0" width="536" height="636"/>
113+ <color key="backgroundColor" white="1" alpha="0.69999999999999996" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
114+ </view>
115+ </subviews>
116+ <constraints>
117+ <constraint firstItem="btD-Wl-3P6" firstAttribute="leading" secondItem="Fw9-l6-N8a" secondAttribute="trailing" constant="-162" id="1lP-Gg-qgW"/>
118+ <constraint firstItem="btD-Wl-3P6" firstAttribute="leading" secondItem="onR-hl-Q2x" secondAttribute="trailing" constant="-162" id="1vg-zK-zAf"/>
119+ <constraint firstItem="Y23-Wu-4BW" firstAttribute="leading" secondItem="BDw-f7-kaJ" secondAttribute="leading" constant="44" id="913-M2-zhQ"/>
120+ <constraint firstItem="btD-Wl-3P6" firstAttribute="leading" secondItem="FuE-LV-NBR" secondAttribute="leading" id="ALg-fi-eby"/>
121+ <constraint firstItem="Fw9-l6-N8a" firstAttribute="top" secondItem="btD-Wl-3P6" secondAttribute="bottom" constant="-286" id="DyF-KK-1VM"/>
122+ <constraint firstItem="btD-Wl-3P6" firstAttribute="top" secondItem="FuE-LV-NBR" secondAttribute="top" id="EKh-3k-EL9"/>
123+ <constraint firstItem="mUw-im-1BC" firstAttribute="top" secondItem="KJZ-Nl-7hH" secondAttribute="bottom" constant="40" id="GaI-BE-NZy"/>
124+ <constraint firstItem="btD-Wl-3P6" firstAttribute="width" secondItem="FuE-LV-NBR" secondAttribute="width" priority="250" id="MDs-kk-aza"/>
125+ <constraint firstItem="btD-Wl-3P6" firstAttribute="top" secondItem="aIM-Qn-Uhl" secondAttribute="bottom" constant="-235" id="NwR-U0-V6F"/>
126+ <constraint firstItem="mUw-im-1BC" firstAttribute="top" secondItem="btD-Wl-3P6" secondAttribute="bottom" constant="-205" id="UXz-DD-dPH"/>
127+ <constraint firstItem="mUw-im-1BC" firstAttribute="leading" secondItem="Fw9-l6-N8a" secondAttribute="trailing" constant="60" id="V4u-ko-iFV"/>
128+ <constraint firstItem="KJZ-Nl-7hH" firstAttribute="top" secondItem="xsw-fJ-8cN" secondAttribute="bottom" constant="40" id="XFV-l2-chC"/>
129+ <constraint firstItem="btD-Wl-3P6" firstAttribute="top" secondItem="onR-hl-Q2x" secondAttribute="bottom" constant="-332" id="XNT-i4-1l8"/>
130+ <constraint firstItem="aIM-Qn-Uhl" firstAttribute="leading" secondItem="xsw-fJ-8cN" secondAttribute="trailing" constant="46" id="XVo-Ke-EGt"/>
131+ <constraint firstAttribute="trailing" secondItem="btD-Wl-3P6" secondAttribute="trailing" id="Ybd-7M-6Ft"/>
132+ <constraint firstItem="wpi-6E-c5p" firstAttribute="leading" secondItem="KJZ-Nl-7hH" secondAttribute="trailing" constant="73" id="cy7-0f-qGh"/>
133+ <constraint firstItem="wpi-6E-c5p" firstAttribute="top" secondItem="aIM-Qn-Uhl" secondAttribute="bottom" constant="40" id="dek-gp-H4X"/>
134+ <constraint firstItem="btD-Wl-3P6" firstAttribute="height" secondItem="FuE-LV-NBR" secondAttribute="height" priority="250" id="fSd-Le-0Bc"/>
135+ <constraint firstAttribute="bottom" secondItem="btD-Wl-3P6" secondAttribute="bottom" id="neR-bl-aSU"/>
136+ <constraint firstItem="KJZ-Nl-7hH" firstAttribute="leading" secondItem="onR-hl-Q2x" secondAttribute="trailing" constant="60" id="pka-Xh-e1c"/>
137+ <constraint firstItem="xsw-fJ-8cN" firstAttribute="leading" secondItem="onR-hl-Q2x" secondAttribute="trailing" constant="47" id="r9E-ps-zBG"/>
138+ <constraint firstItem="Y23-Wu-4BW" firstAttribute="top" secondItem="BDw-f7-kaJ" secondAttribute="top" constant="37" id="rgb-Sa-T0E"/>
139+ </constraints>
140+ <viewLayoutGuide key="contentLayoutGuide" id="BDw-f7-kaJ"/>
141+ <viewLayoutGuide key="frameLayoutGuide" id="KRK-7M-mdV"/>
142+ </scrollView>
143+ </subviews>
144+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
145+ <constraints>
146+ <constraint firstItem="FuE-LV-NBR" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="0zj-Rn-Ogr"/>
147+ <constraint firstItem="FuE-LV-NBR" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="87c-vf-vMB"/>
148+ <constraint firstItem="btD-Wl-3P6" firstAttribute="trailing" secondItem="zbE-1g-Qz4" secondAttribute="trailing" id="ASF-YJ-jez"/>
149+ <constraint firstItem="zbE-1g-Qz4" firstAttribute="leading" secondItem="btD-Wl-3P6" secondAttribute="leading" id="Ec8-Qz-Dn3"/>
150+ <constraint firstItem="btD-Wl-3P6" firstAttribute="bottom" secondItem="zbE-1g-Qz4" secondAttribute="bottom" id="UFk-wW-dCx"/>
151+ <constraint firstItem="FuE-LV-NBR" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="bhi-Ox-g2b"/>
152+ <constraint firstItem="zbE-1g-Qz4" firstAttribute="top" secondItem="btD-Wl-3P6" secondAttribute="top" id="j32-id-sD4"/>
153+ <constraint firstItem="FuE-LV-NBR" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="jLf-Pz-gy1"/>
154+ </constraints>
155+ <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
156+ <connections>
157+ <outlet property="eighthTable" destination="mUw-im-1BC" id="x44-wS-xJg"/>
158+ <outlet property="fifthTable" destination="KJZ-Nl-7hH" id="KXs-8a-Fo8"/>
159+ <outlet property="firstTable" destination="Y23-Wu-4BW" id="9m3-Oy-Gwc"/>
160+ <outlet property="forthTable" destination="wpi-6E-c5p" id="26b-bH-kEA"/>
161+ <outlet property="image" destination="btD-Wl-3P6" id="Ou2-hT-jap"/>
162+ <outlet property="scrollView" destination="FuE-LV-NBR" id="pWc-cI-eXE"/>
163+ <outlet property="secondTable" destination="xsw-fJ-8cN" id="2vH-LX-qF0"/>
164+ <outlet property="seventhTable" destination="Fw9-l6-N8a" id="Jwb-yY-Opx"/>
165+ <outlet property="shadow" destination="zbE-1g-Qz4" id="tHA-7d-6Aa"/>
166+ <outlet property="sixthTable" destination="onR-hl-Q2x" id="Zi7-hJ-KLq"/>
167+ <outlet property="trirdTable" destination="aIM-Qn-Uhl" id="aFd-cB-neE"/>
168+ </connections>
169+ <point key="canvasLocation" x="-194.40000000000001" y="97.601199400299862"/>
170+ </view>
171+ </objects>
172+ <resources>
173+ <image name="map_1" width="536" height="636"/>
174+ </resources>
175+</document>
Hookah Tau/Controllers/Client/Reservations/Maps/2/MapView2.swiftnew file+152
@@ -0,0 +1,152 @@
1+//
2+// MapView2.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 28/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class MapView2: MapImageScroll {
12+
13+ // MARK: - Tables
14+
15+ @IBOutlet weak var table2: TableButton! {
16+ didSet {
17+ let style = TableButtonStyle()
18+ style.apply(to: table2)
19+ }
20+ }
21+
22+ @IBOutlet weak var table3: TableButton!{
23+ didSet {
24+ let style = TableButtonStyle()
25+ style.apply(to: table3)
26+ }
27+ }
28+
29+ @IBOutlet weak var table4: TableButton! {
30+ didSet {
31+ let style = TableButtonStyle()
32+ style.apply(to: table4)
33+ }
34+ }
35+
36+ @IBOutlet weak var table5: TableButton! {
37+ didSet {
38+ let style = TableButtonStyle()
39+ style.apply(to: table5)
40+ }
41+ }
42+
43+ @IBOutlet weak var table6: TableButton! {
44+ didSet {
45+ let style = TableButtonStyle()
46+ style.apply(to: table6)
47+ }
48+ }
49+
50+ @IBOutlet weak var table7: TableButton! {
51+ didSet {
52+ let style = TableButtonStyle()
53+ style.apply(to: table7)
54+ }
55+ }
56+
57+ @IBOutlet weak var table8: TableButton! {
58+ didSet {
59+ let style = TableButtonStyle()
60+ style.apply(to: table8)
61+ }
62+ }
63+
64+ override var handler: MapHandler? {
65+ didSet {
66+ handleTap(button: table8, id: 8)
67+ }
68+ }
69+
70+ // MARK: - Super props
71+
72+ @IBOutlet weak var scrollView: UIScrollView! {
73+ didSet {
74+ super.scrollViewParent = scrollView
75+ }
76+ }
77+
78+ @IBOutlet weak var image: UIImageView! {
79+ didSet {
80+ super.img = image
81+ }
82+ }
83+
84+ @IBOutlet weak var shadow: UIView! {
85+ didSet {
86+ super.shadowView = shadow
87+ shadow.alpha = 0
88+ }
89+ }
90+
91+ // MARK: - Lifecycle
92+
93+ override func awakeFromNib() {
94+ super.awakeFromNib()
95+
96+ self.scrollView.delegate = self
97+ self.scrollView.delaysContentTouches = false
98+
99+ tables[2] = table2
100+ tables[3] = table3
101+ tables[4] = table4
102+ tables[5] = table5
103+ tables[6] = table6
104+ tables[7] = table7
105+ tables[8] = table8
106+
107+ tables.values.forEach { image.addSubview($0) }
108+ image.addSubview(shadowView)
109+
110+ configureFor(image.frame.size)
111+ }
112+
113+ // MARK: - Taps
114+
115+ @IBAction func tap2(_ sender: TableButton) {
116+ handleTap(button: sender, id: 2)
117+ }
118+
119+ @IBAction func tap3(_ sender: TableButton) {
120+ handleTap(button: sender, id: 3)
121+ }
122+
123+ @IBAction func tap4(_ sender: TableButton) {
124+ handleTap(button: sender, id: 4)
125+ }
126+
127+ @IBAction func tap5(_ sender: TableButton) {
128+ handleTap(button: sender, id: 5)
129+ }
130+
131+ @IBAction func tap6(_ sender: TableButton) {
132+ handleTap(button: sender, id: 6)
133+ }
134+
135+ @IBAction func tap7(_ sender: TableButton) {
136+ handleTap(button: sender, id: 7)
137+ }
138+
139+ @IBAction func tap8(_ sender: TableButton) {
140+ handleTap(button: sender, id: 8)
141+ }
142+
143+}
144+
145+// MARK: - Scroll view
146+
147+extension MapView2: UIScrollViewDelegate {
148+
149+ func viewForZooming(in scrollView: UIScrollView) -> UIView? {
150+ self.image
151+ }
152+}
Hookah Tau/Controllers/Client/Reservations/Maps/2/MapView2.xibnew file+155
@@ -0,0 +1,155 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina4_7" orientation="portrait" appearance="light"/>
4+ <dependencies>
5+ <deployment identifier="iOS"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9+ </dependencies>
10+ <objects>
11+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
12+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
13+ <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="MapView2" customModule="Hookah_Tau" customModuleProvider="target">
14+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
15+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
16+ <subviews>
17+ <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="emi-wK-dKY">
18+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
19+ <subviews>
20+ <imageView clipsSubviews="YES" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="map_2" translatesAutoresizingMaskIntoConstraints="NO" id="Obf-Cs-bNe">
21+ <rect key="frame" x="0.0" y="0.0" width="683" height="329"/>
22+ </imageView>
23+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="N1V-4M-SuG" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
24+ <rect key="frame" x="70" y="18" width="92" height="66"/>
25+ <constraints>
26+ <constraint firstAttribute="width" constant="92" id="Cd4-io-y5G"/>
27+ <constraint firstAttribute="height" constant="66" id="wSz-LG-S6h"/>
28+ </constraints>
29+ <connections>
30+ <action selector="tap8:" destination="iN0-l3-epB" eventType="touchUpInside" id="23l-0c-N7c"/>
31+ </connections>
32+ </button>
33+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2KA-Fl-otO" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
34+ <rect key="frame" x="190" y="17" width="104" height="95"/>
35+ <constraints>
36+ <constraint firstAttribute="height" constant="95" id="aIs-ch-V6c"/>
37+ <constraint firstAttribute="width" constant="104" id="vje-NJ-ttB"/>
38+ </constraints>
39+ <connections>
40+ <action selector="tap7:" destination="iN0-l3-epB" eventType="touchUpInside" id="GuY-TU-Mbv"/>
41+ </connections>
42+ </button>
43+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Uyw-7g-fgk" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
44+ <rect key="frame" x="190" y="190" width="68" height="94"/>
45+ <constraints>
46+ <constraint firstAttribute="width" constant="68" id="IyU-Gp-dLh"/>
47+ <constraint firstAttribute="height" constant="94" id="N7G-Ua-jrx"/>
48+ </constraints>
49+ <connections>
50+ <action selector="tap4:" destination="iN0-l3-epB" eventType="touchUpInside" id="mUZ-2d-VkM"/>
51+ </connections>
52+ </button>
53+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Sko-xU-trE" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
54+ <rect key="frame" x="286" y="177" width="103" height="118"/>
55+ <constraints>
56+ <constraint firstAttribute="width" constant="103" id="7QV-8e-19v"/>
57+ <constraint firstAttribute="height" constant="118" id="ApA-IR-eB1"/>
58+ </constraints>
59+ <connections>
60+ <action selector="tap3:" destination="iN0-l3-epB" eventType="touchUpInside" id="Vx6-bj-c44"/>
61+ </connections>
62+ </button>
63+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="pMi-ey-nl3" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
64+ <rect key="frame" x="323" y="18" width="102" height="95"/>
65+ <constraints>
66+ <constraint firstAttribute="width" constant="102" id="9Pn-tv-fnZ"/>
67+ <constraint firstAttribute="height" constant="95" id="PXg-Gy-7TO"/>
68+ </constraints>
69+ <connections>
70+ <action selector="tap6:" destination="iN0-l3-epB" eventType="touchUpInside" id="ge0-j5-gLW"/>
71+ </connections>
72+ </button>
73+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="S2Z-ye-LWO" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
74+ <rect key="frame" x="455" y="18" width="102" height="94"/>
75+ <constraints>
76+ <constraint firstAttribute="width" constant="102" id="E4e-Gs-QYc"/>
77+ <constraint firstAttribute="height" constant="94" id="NLu-i5-Mr6"/>
78+ </constraints>
79+ <connections>
80+ <action selector="tap5:" destination="iN0-l3-epB" eventType="touchUpInside" id="LkA-Xo-cwd"/>
81+ </connections>
82+ </button>
83+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QLb-ch-cuY" customClass="TableButton" customModule="Hookah_Tau" customModuleProvider="target">
84+ <rect key="frame" x="426" y="164" width="131" height="146"/>
85+ <constraints>
86+ <constraint firstAttribute="width" constant="131" id="I3b-2n-Bgm"/>
87+ <constraint firstAttribute="height" constant="146" id="Tlu-Sy-7GC"/>
88+ </constraints>
89+ <connections>
90+ <action selector="tap2:" destination="iN0-l3-epB" eventType="touchUpInside" id="7N9-GF-PKo"/>
91+ </connections>
92+ </button>
93+ <view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Kvb-P4-fah">
94+ <rect key="frame" x="0.0" y="0.0" width="683" height="329"/>
95+ <color key="backgroundColor" white="1" alpha="0.6951519691780822" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
96+ </view>
97+ </subviews>
98+ <constraints>
99+ <constraint firstItem="Sko-xU-trE" firstAttribute="top" secondItem="pMi-ey-nl3" secondAttribute="bottom" constant="64" id="6aW-Tf-64S"/>
100+ <constraint firstItem="2KA-Fl-otO" firstAttribute="leading" secondItem="N1V-4M-SuG" secondAttribute="trailing" constant="28" id="7Ei-ax-wx6"/>
101+ <constraint firstItem="N1V-4M-SuG" firstAttribute="leading" secondItem="Obf-Cs-bNe" secondAttribute="leading" constant="70" id="7Rw-z2-eKD"/>
102+ <constraint firstItem="2KA-Fl-otO" firstAttribute="top" secondItem="Obf-Cs-bNe" secondAttribute="top" constant="17" id="Cos-le-6UH"/>
103+ <constraint firstItem="Obf-Cs-bNe" firstAttribute="trailing" secondItem="QLb-ch-cuY" secondAttribute="trailing" constant="126" id="FhV-De-jji"/>
104+ <constraint firstItem="Obf-Cs-bNe" firstAttribute="height" secondItem="emi-wK-dKY" secondAttribute="height" priority="250" id="H4t-Mm-gPX"/>
105+ <constraint firstItem="QLb-ch-cuY" firstAttribute="top" secondItem="S2Z-ye-LWO" secondAttribute="bottom" constant="52" id="HJJ-ia-caS"/>
106+ <constraint firstItem="Uyw-7g-fgk" firstAttribute="top" secondItem="2KA-Fl-otO" secondAttribute="bottom" constant="78" id="MOn-dn-UV6"/>
107+ <constraint firstItem="Kvb-P4-fah" firstAttribute="trailing" secondItem="Obf-Cs-bNe" secondAttribute="trailing" id="N0a-np-nCu"/>
108+ <constraint firstItem="Sko-xU-trE" firstAttribute="leading" secondItem="Uyw-7g-fgk" secondAttribute="trailing" constant="28" id="SRb-lA-XTw"/>
109+ <constraint firstAttribute="trailing" secondItem="Obf-Cs-bNe" secondAttribute="trailing" id="Saf-Tc-0J5"/>
110+ <constraint firstItem="pMi-ey-nl3" firstAttribute="top" secondItem="Obf-Cs-bNe" secondAttribute="top" constant="18" id="Vov-VH-rha"/>
111+ <constraint firstAttribute="bottom" secondItem="Obf-Cs-bNe" secondAttribute="bottom" id="WPI-RB-B4A"/>
112+ <constraint firstItem="Kvb-P4-fah" firstAttribute="leading" secondItem="Obf-Cs-bNe" secondAttribute="leading" id="YgQ-Rl-iQD"/>
113+ <constraint firstItem="Kvb-P4-fah" firstAttribute="top" secondItem="Obf-Cs-bNe" secondAttribute="top" id="aPY-ua-gcI"/>
114+ <constraint firstItem="pMi-ey-nl3" firstAttribute="leading" secondItem="2KA-Fl-otO" secondAttribute="trailing" constant="29" id="aR4-Q4-cQ3"/>
115+ <constraint firstItem="Obf-Cs-bNe" firstAttribute="width" secondItem="emi-wK-dKY" secondAttribute="width" priority="250" id="dkc-x7-EPa"/>
116+ <constraint firstItem="S2Z-ye-LWO" firstAttribute="top" secondItem="Obf-Cs-bNe" secondAttribute="top" constant="18" id="e7Q-BO-paM"/>
117+ <constraint firstItem="S2Z-ye-LWO" firstAttribute="leading" secondItem="pMi-ey-nl3" secondAttribute="trailing" constant="30" id="kwk-Ex-x1d"/>
118+ <constraint firstItem="Kvb-P4-fah" firstAttribute="bottom" secondItem="Obf-Cs-bNe" secondAttribute="bottom" id="nF9-OF-52s"/>
119+ <constraint firstItem="QLb-ch-cuY" firstAttribute="leading" secondItem="Sko-xU-trE" secondAttribute="trailing" constant="37" id="pYH-nL-sHE"/>
120+ <constraint firstItem="N1V-4M-SuG" firstAttribute="top" secondItem="Obf-Cs-bNe" secondAttribute="top" constant="18" id="uVj-fC-gUh"/>
121+ <constraint firstItem="Obf-Cs-bNe" firstAttribute="top" secondItem="emi-wK-dKY" secondAttribute="top" id="uXg-WE-LVS"/>
122+ <constraint firstItem="Obf-Cs-bNe" firstAttribute="leading" secondItem="emi-wK-dKY" secondAttribute="leading" id="zgm-8D-6cN"/>
123+ </constraints>
124+ <viewLayoutGuide key="contentLayoutGuide" id="heY-yN-cxj"/>
125+ <viewLayoutGuide key="frameLayoutGuide" id="Si0-40-mPV"/>
126+ </scrollView>
127+ </subviews>
128+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
129+ <constraints>
130+ <constraint firstItem="emi-wK-dKY" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="0jl-ST-MHN"/>
131+ <constraint firstItem="emi-wK-dKY" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="AsB-3G-0nu"/>
132+ <constraint firstItem="emi-wK-dKY" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="g8Y-gE-OhP"/>
133+ <constraint firstItem="emi-wK-dKY" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="rLX-cv-To7"/>
134+ </constraints>
135+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
136+ <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
137+ <connections>
138+ <outlet property="image" destination="Obf-Cs-bNe" id="X9U-1H-cye"/>
139+ <outlet property="scrollView" destination="emi-wK-dKY" id="9ZQ-1W-Ig5"/>
140+ <outlet property="shadow" destination="Kvb-P4-fah" id="Qaa-1I-iuh"/>
141+ <outlet property="table2" destination="QLb-ch-cuY" id="13h-54-jLj"/>
142+ <outlet property="table3" destination="Sko-xU-trE" id="6rG-Ov-XI4"/>
143+ <outlet property="table4" destination="Uyw-7g-fgk" id="je7-hC-uEg"/>
144+ <outlet property="table5" destination="S2Z-ye-LWO" id="WjB-f2-q3D"/>
145+ <outlet property="table6" destination="pMi-ey-nl3" id="XsT-cC-4o9"/>
146+ <outlet property="table7" destination="2KA-Fl-otO" id="baj-Ek-51Q"/>
147+ <outlet property="table8" destination="N1V-4M-SuG" id="8a7-Kv-JqN"/>
148+ </connections>
149+ <point key="canvasLocation" x="138.40000000000001" y="120.98950524737631"/>
150+ </view>
151+ </objects>
152+ <resources>
153+ <image name="map_2" width="683" height="329"/>
154+ </resources>
155+</document>
Hookah Tau/Controllers/Client/Reservations/Maps/MapView.swiftnew file+102
@@ -0,0 +1,102 @@
1+//
2+// MapView.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 06/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+
12+class MapImageScroll: UIView {
13+
14+ weak var handler: MapHandler?
15+
16+ var scrollViewParent: UIScrollView!
17+
18+ var shadowView: UIView!
19+
20+ var img: UIImageView!
21+
22+ var tables: [Int: TableButton] = [:]
23+
24+ var zoomScale: CGFloat = 1.2
25+
26+ func scrollToTable(table: Int) {
27+ guard let tableButton = tables[table] else { return }
28+
29+ tableButton.select()
30+ img.bringSubviewToFront(shadowView)
31+ img.bringSubviewToFront(tableButton)
32+
33+ shadowView.alpha = 1
34+
35+ scrollViewParent.zoom(to: tableButton.frame, animated: true)
36+ scrollViewParent.setZoomScale(zoomScale, animated: true)
37+ }
38+
39+ func scrollBack() {
40+ img.sendSubviewToBack(shadowView)
41+ shadowView.alpha = 0
42+ }
43+
44+ func configureFor(_ imageSize: CGSize) {
45+ self.scrollViewParent.contentSize = imageSize
46+ setMaxMinZoomScaleForCurrentBounds()
47+ }
48+
49+ func setMaxMinZoomScaleForCurrentBounds() {
50+ let boundsSize = self.scrollViewParent.bounds.size
51+ let imageSize = img.bounds.size
52+
53+ //1. calculate minimumZoomscale
54+ let xScale = boundsSize.width / imageSize.width
55+ let yScale = boundsSize.height / imageSize.height
56+ var minScale = min(xScale, yScale)
57+
58+ //2. calculate maximumZoomscale
59+ var maxScale: CGFloat = 1.0
60+ if minScale < 0.1 {
61+ maxScale = 0.3
62+ }
63+ if minScale >= 0.1 && minScale < 0.5 {
64+ maxScale = 0.7
65+ }
66+ if minScale >= 0.5 {
67+ maxScale = max(1.0, minScale)
68+ }
69+
70+ if img.frame.width < frame.width {
71+ let scaleW = frame.width / img.frame.width
72+ minScale = scaleW
73+ }
74+
75+ if img.frame.height < frame.height {
76+ let scaleH = frame.height / img.frame.height
77+ maxScale = scaleH
78+ }
79+
80+ img.transform = CGAffineTransform(scaleX: minScale, y: minScale)
81+
82+ self.scrollViewParent.maximumZoomScale = maxScale
83+ self.scrollViewParent.minimumZoomScale = minScale
84+ }
85+
86+ // Method for handling button taps.
87+ func handleTap(button: TableButton, id: Int) {
88+ tables.values.forEach { $0.unselect() }
89+ button.select()
90+ handler?.handleTap(withId: id)
91+ }
92+}
93+
94+extension MapImageScroll {
95+
96+ func performUpdate(inactive: [Int]) {
97+
98+ let active = Set(tables.keys).subtracting(inactive)
99+ active.forEach { ind in tables[ind]?.active() }
100+ inactive.forEach { ind in tables[ind]?.inactive() }
101+ }
102+}
Hookah Tau/Controllers/Client/Reservations/Reservation.storyboardnew file+158
@@ -0,0 +1,158 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina6_1" orientation="portrait" appearance="light"/>
4+ <dependencies>
5+ <deployment identifier="iOS"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9+ </dependencies>
10+ <scenes>
11+ <!--First Step Reservation View Controller-->
12+ <scene sceneID="EKz-nU-dQ1">
13+ <objects>
14+ <viewController storyboardIdentifier="ReservationViewController" id="Fha-pE-okd" customClass="FirstStepReservationViewController" customModule="Hookah_Tau" customModuleProvider="target" sceneMemberID="viewController">
15+ <view key="view" contentMode="scaleToFill" id="cwG-Fa-gXD">
16+ <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
17+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
18+ <subviews>
19+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RRF-jh-Xme">
20+ <rect key="frame" x="0.0" y="671" width="414" height="225"/>
21+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
22+ <constraints>
23+ <constraint firstAttribute="height" constant="225" id="43Q-xl-4hv"/>
24+ </constraints>
25+ </view>
26+ </subviews>
27+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
28+ <constraints>
29+ <constraint firstItem="RRF-jh-Xme" firstAttribute="leading" secondItem="MXi-ad-tf6" secondAttribute="leading" id="Bs8-yy-Zht"/>
30+ <constraint firstAttribute="bottom" secondItem="RRF-jh-Xme" secondAttribute="bottom" id="KZv-en-hrr"/>
31+ <constraint firstItem="RRF-jh-Xme" firstAttribute="trailing" secondItem="MXi-ad-tf6" secondAttribute="trailing" id="ehP-xe-Opz"/>
32+ </constraints>
33+ <viewLayoutGuide key="safeArea" id="MXi-ad-tf6"/>
34+ </view>
35+ <connections>
36+ <outlet property="childContentView" destination="RRF-jh-Xme" id="blV-8a-srQ"/>
37+ </connections>
38+ </viewController>
39+ <placeholder placeholderIdentifier="IBFirstResponder" id="TB1-Hv-wQ6" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
40+ </objects>
41+ <point key="canvasLocation" x="-140.57971014492756" y="-38.169642857142854"/>
42+ </scene>
43+ <!--Second Step Reservation View Controller-->
44+ <scene sceneID="NON-tn-ls5">
45+ <objects>
46+ <viewController storyboardIdentifier="SecondStepReservationViewController" id="OAC-Ui-1o4" customClass="SecondStepReservationViewController" customModule="Hookah_Tau" customModuleProvider="target" sceneMemberID="viewController">
47+ <view key="view" contentMode="scaleToFill" id="dZe-8U-Rs6">
48+ <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
49+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
50+ <subviews>
51+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NBJ-7w-vpV">
52+ <rect key="frame" x="0.0" y="502" width="414" height="394"/>
53+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
54+ <constraints>
55+ <constraint firstAttribute="height" constant="394" id="KKm-d5-Srx"/>
56+ </constraints>
57+ </view>
58+ </subviews>
59+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
60+ <constraints>
61+ <constraint firstItem="NBJ-7w-vpV" firstAttribute="leading" secondItem="YKO-1X-SYz" secondAttribute="leading" id="ZCK-Y0-Dnb"/>
62+ <constraint firstItem="NBJ-7w-vpV" firstAttribute="trailing" secondItem="YKO-1X-SYz" secondAttribute="trailing" id="ulb-DD-Mmh"/>
63+ <constraint firstAttribute="bottom" secondItem="NBJ-7w-vpV" secondAttribute="bottom" id="zEI-rl-4r7"/>
64+ </constraints>
65+ <viewLayoutGuide key="safeArea" id="YKO-1X-SYz"/>
66+ </view>
67+ <connections>
68+ <outlet property="childContentView" destination="NBJ-7w-vpV" id="aa6-nY-PUA"/>
69+ </connections>
70+ </viewController>
71+ <placeholder placeholderIdentifier="IBFirstResponder" id="rVf-H4-jP0" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
72+ </objects>
73+ <point key="canvasLocation" x="706" y="-38"/>
74+ </scene>
75+ <!--Third Step Reservation View Controller-->
76+ <scene sceneID="zRo-J6-3SG">
77+ <objects>
78+ <viewController storyboardIdentifier="ThirdStepReservationViewController" id="BZu-JB-b3i" customClass="ThirdStepReservationViewController" customModule="Hookah_Tau" customModuleProvider="target" sceneMemberID="viewController">
79+ <view key="view" contentMode="scaleToFill" id="3b8-mw-Gl1">
80+ <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
81+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
82+ <subviews>
83+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e2X-iN-FVj">
84+ <rect key="frame" x="0.0" y="556" width="414" height="340"/>
85+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
86+ <constraints>
87+ <constraint firstAttribute="height" constant="340" id="5U9-DA-Asv"/>
88+ </constraints>
89+ </view>
90+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lUx-gC-C8T">
91+ <rect key="frame" x="0.0" y="44" width="414" height="512"/>
92+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
93+ </view>
94+ </subviews>
95+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
96+ <constraints>
97+ <constraint firstItem="e2X-iN-FVj" firstAttribute="top" secondItem="lUx-gC-C8T" secondAttribute="bottom" id="3gm-hP-Bdu"/>
98+ <constraint firstItem="e2X-iN-FVj" firstAttribute="trailing" secondItem="gXx-re-YYI" secondAttribute="trailing" id="3mf-Ee-0xt"/>
99+ <constraint firstItem="e2X-iN-FVj" firstAttribute="leading" secondItem="gXx-re-YYI" secondAttribute="leading" id="H2H-uv-zpb"/>
100+ <constraint firstItem="gXx-re-YYI" firstAttribute="trailing" secondItem="lUx-gC-C8T" secondAttribute="trailing" id="N8u-eH-14m"/>
101+ <constraint firstAttribute="bottom" secondItem="e2X-iN-FVj" secondAttribute="bottom" id="nQM-9e-gfE"/>
102+ <constraint firstItem="lUx-gC-C8T" firstAttribute="leading" secondItem="gXx-re-YYI" secondAttribute="leading" id="oir-mE-qlS"/>
103+ <constraint firstItem="gXx-re-YYI" firstAttribute="top" secondItem="lUx-gC-C8T" secondAttribute="top" id="zDp-B5-m8M"/>
104+ </constraints>
105+ <viewLayoutGuide key="safeArea" id="gXx-re-YYI"/>
106+ </view>
107+ <connections>
108+ <outlet property="containerView" destination="e2X-iN-FVj" id="6Zy-M4-sSA"/>
109+ <outlet property="contentForMap" destination="lUx-gC-C8T" id="LBl-cs-Yav"/>
110+ </connections>
111+ </viewController>
112+ <placeholder placeholderIdentifier="IBFirstResponder" id="En2-ct-Lfj" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
113+ </objects>
114+ <point key="canvasLocation" x="1457.9710144927537" y="-38.169642857142854"/>
115+ </scene>
116+ <!--Change Reservation View Controller-->
117+ <scene sceneID="zZt-Ob-8J3">
118+ <objects>
119+ <viewController storyboardIdentifier="ChangeReservationViewController" id="qmR-St-vh2" customClass="ChangeReservationViewController" customModule="Hookah_Tau" customModuleProvider="target" sceneMemberID="viewController">
120+ <view key="view" contentMode="scaleToFill" id="mnl-c9-WGz">
121+ <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
122+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
123+ <subviews>
124+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kon-kQ-rMb">
125+ <rect key="frame" x="0.0" y="502" width="414" height="394"/>
126+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
127+ <constraints>
128+ <constraint firstAttribute="height" constant="394" id="Ppm-PI-ASV"/>
129+ </constraints>
130+ </view>
131+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6Dy-xy-vQH">
132+ <rect key="frame" x="0.0" y="0.0" width="414" height="502"/>
133+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
134+ </view>
135+ </subviews>
136+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
137+ <constraints>
138+ <constraint firstItem="kon-kQ-rMb" firstAttribute="leading" secondItem="Oj9-9F-isg" secondAttribute="leading" id="5wF-Rc-6Na"/>
139+ <constraint firstAttribute="bottom" secondItem="kon-kQ-rMb" secondAttribute="bottom" id="IAO-aj-hyT"/>
140+ <constraint firstItem="kon-kQ-rMb" firstAttribute="top" secondItem="6Dy-xy-vQH" secondAttribute="bottom" id="W6B-dA-vrO"/>
141+ <constraint firstItem="6Dy-xy-vQH" firstAttribute="leading" secondItem="Oj9-9F-isg" secondAttribute="leading" id="WKh-xt-L3z"/>
142+ <constraint firstItem="kon-kQ-rMb" firstAttribute="trailing" secondItem="Oj9-9F-isg" secondAttribute="trailing" id="cZG-IB-ohm"/>
143+ <constraint firstItem="6Dy-xy-vQH" firstAttribute="top" secondItem="mnl-c9-WGz" secondAttribute="top" id="iK5-6K-mEo"/>
144+ <constraint firstItem="6Dy-xy-vQH" firstAttribute="trailing" secondItem="Oj9-9F-isg" secondAttribute="trailing" id="rrY-dK-bTz"/>
145+ </constraints>
146+ <viewLayoutGuide key="safeArea" id="Oj9-9F-isg"/>
147+ </view>
148+ <connections>
149+ <outlet property="childContentView" destination="kon-kQ-rMb" id="5DH-RF-lEQ"/>
150+ <outlet property="mapContentView" destination="6Dy-xy-vQH" id="5Cu-uI-WT3"/>
151+ </connections>
152+ </viewController>
153+ <placeholder placeholderIdentifier="IBFirstResponder" id="H8g-xl-PmS" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
154+ </objects>
155+ <point key="canvasLocation" x="2350.7246376811595" y="-38.169642857142854"/>
156+ </scene>
157+ </scenes>
158+</document>
Hookah Tau/Controllers/Client/Reservations/Steps/1/FirstStepReservationCoordinator.swiftnew file+59
@@ -0,0 +1,59 @@
1+//
2+// ReservationCoordinator.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 06/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class FirstStepReservationCoordinator: BaseCoordinator {
12+
13+ // MARK: - Properties
14+
15+ var didFinish: (() -> Void)?
16+
17+ var establishment: Int = 1
18+
19+ // MARK: - Lifecycle
20+
21+ override func start() {
22+ let storyboard = UIStoryboard(name: "Reservation", bundle: nil)
23+ let reservationVC = storyboard.instantiateViewController(withIdentifier: "ReservationViewController") as! FirstStepReservationViewController
24+
25+ reservationVC.coordinator = self
26+ reservationVC.establishmentId = establishment
27+
28+ navigationController?.pushViewController(reservationVC, animated: true)
29+ }
30+
31+ func makeReservation(model: SecondStepModel,
32+ mapView: MapImageScroll?) {
33+
34+ let reservationCoordinator =
35+ SecondStepReservationCoordinator(navigationController: navigationController)
36+
37+ reservationCoordinator.model = model
38+ reservationCoordinator.mapView = mapView
39+
40+ addDependency(reservationCoordinator)
41+
42+ reservationCoordinator.didFinish = {
43+ self.navigationController?.popViewController(animated: false)
44+ self.removeDependency(reservationCoordinator)
45+ self.didFinish?()
46+ }
47+
48+ reservationCoordinator.goBack = { [weak self] mapView in
49+
50+ self?.navigationController?.popViewController(animated: false)
51+ self?.removeDependency(reservationCoordinator)
52+ if let vv = self?.navigationController?.topViewController as? FirstStepReservationViewController {
53+ vv.mapView = mapView
54+ }
55+ }
56+
57+ reservationCoordinator.start()
58+ }
59+}
Hookah Tau/Controllers/Client/Reservations/Steps/1/FirstStepReservationViewController.swiftnew file+191
@@ -0,0 +1,191 @@
1+//
2+// ReservationViewController.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 06/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+
12+class FirstStepReservationViewController: BaseViewController {
13+
14+ // MARK: - Properties
15+
16+ weak var coordinator: FirstStepReservationCoordinator?
17+
18+ @IBOutlet weak var childContentView: UIView!
19+
20+ var firstStepView: FirstStepView?
21+
22+ var tableId: Int = 2
23+
24+ var reservationsService: ReservationsService?
25+
26+ var mapView: MapImageScroll? {
27+ didSet {
28+ view.addSubviewThatFills(mapView)
29+ guard let map = mapView else { return }
30+ map.scrollViewParent.contentInset = UIEdgeInsets(top: 0,
31+ left: 0,
32+ bottom: childContentView.frame.height,
33+ right: 0)
34+ map.isUserInteractionEnabled = true
35+ map.scrollViewParent.setZoomScale(0.5, animated: true)
36+ map.scrollBack()
37+ view.sendSubviewToBack(map)
38+ }
39+ }
40+
41+ var allReservations: AllReservations? {
42+ didSet {
43+ guard let _ = allReservations else {
44+ return
45+ }
46+
47+ updateChildViewControllerWithChosenId(tableId)
48+ }
49+ }
50+
51+ let continueButton: Button = {
52+ let button = Button()
53+ let style = BlackButtonStyle()
54+ style.apply(to: button, withTitle: "ЗАБРОНИРОВАТЬ")
55+ return button
56+ }()
57+
58+ let callButton: Button = {
59+ let button = Button()
60+ let style = BlackButtonStyle()
61+ style.apply(to: button, withTitle: "ПОЗВОНИТЬ")
62+ return button
63+ }()
64+
65+ var establishmentId: Int = 1
66+
67+ // MARK: - Lifecycle
68+
69+ override func viewDidLoad() {
70+ super.viewDidLoad()
71+
72+ configureMap()
73+ setupChildContainer()
74+
75+ setupButtons()
76+
77+ reservationsService = ReservationsService(apiClient: APIClient.shared)
78+
79+ performUpdate()
80+
81+ navigationItem.title = TotalStorage.standard.getEstablishment(establishmentId)?.address
82+ }
83+
84+ func setupButtons() {
85+ addStackViewWithButtons(leftBtn: callButton,
86+ rightBtn: continueButton,
87+ constant: -childContentView.frame.height - 20)
88+
89+ continueButton.addTarget(self, action: #selector(continueBooking), for: .touchUpInside)
90+ callButton.addTarget(self, action: #selector(call), for: .touchUpInside)
91+ }
92+
93+ func performUpdate() {
94+ reservationsService?.getAllReservations(establishmentID: establishmentId, completion: { [weak self] result in
95+ switch result {
96+ case .failure(let err):
97+ self?.displayAlert(forError: err)
98+ case .success(let allReservations):
99+ self?.allReservations = allReservations
100+ }
101+ })
102+ }
103+
104+ override func viewDidAppear(_ animated: Bool) {
105+ super.viewDidAppear(animated)
106+
107+ firstStepView?.setContent()
108+ }
109+
110+ override func viewWillAppear(_ animated: Bool) {
111+ super.viewWillAppear(animated)
112+
113+ tabBarController?.tabBar.isHidden = true
114+ }
115+
116+ func configureMap() {
117+ if establishmentId == 1 {
118+ mapView = MapView1.loadFromNib()
119+ } else if establishmentId == 2 {
120+ mapView = MapView2.loadFromNib()
121+ }
122+ mapView?.handler = self
123+ }
124+
125+ func setupChildContainer() {
126+ firstStepView = FirstStepView.loadFromNib()
127+ firstStepView?.mapUpdater = self
128+ childContentView.addSubviewThatFills(firstStepView)
129+ }
130+
131+ func updateChildViewControllerWithChosenId(_ id: Int) {
132+ let reservationsForTable = allReservations?.reservations[id] ?? []
133+ firstStepView?.setUp(reservationsForTable)
134+ }
135+
136+ // MARK: - button handlers
137+
138+ @objc func continueBooking() {
139+ let map = mapView
140+
141+ guard let startTime = firstStepView?.fullDate else { return }
142+ let isAdmin = DataStorage.standard.getUserModel()?.isAdmin ?? false
143+
144+ let (start, end) = isAdmin ? startTime.getAdminStartingAndEndPoint() : startTime.getClientStartingAndEndPoint()
145+
146+ let reservPeriods = HFunc.main.filterPeriodsStartEndDates(allReservations?.reservations[tableId] ?? [],
147+ start,
148+ end)
149+
150+ let model = SecondStepModel(establishment: establishmentId,
151+ table: tableId,
152+ startTime: startTime,
153+ reservedintervals: reservPeriods)
154+
155+ coordinator?.makeReservation(model: model,
156+ mapView: map)
157+ }
158+
159+ @objc func call() {
160+ guard
161+ let phone = TotalStorage.standard.getEstablishment(establishmentId)?.admin,
162+ let urlPhone = URL(string: "tel://79\(phone)") else { return }
163+
164+ UIApplication.shared.open(urlPhone)
165+ }
166+}
167+
168+extension FirstStepReservationViewController: MapHandler {
169+ func handleTap(withId id: Int) {
170+ tableId = id
171+ updateChildViewControllerWithChosenId(id)
172+ }
173+}
174+
175+extension FirstStepReservationViewController: MapUpdater {
176+ ///
177+ func update(_ date: Date) {
178+ let areBooked = allReservations?.intervals[date] ?? []
179+
180+ let isAdmin = DataStorage.standard.getUserModel()?.isAdmin ?? false
181+ let closed = isAdmin || date.isInClosingHours()
182+
183+ if Set(areBooked).contains(tableId) || closed {
184+ continueButton.availiable = false
185+ } else {
186+ continueButton.availiable = true
187+ }
188+
189+ mapView?.performUpdate(inactive: areBooked)
190+ }
191+}
Hookah Tau/Controllers/Client/Reservations/Steps/1/FirstStepView.swiftnew file+291
@@ -0,0 +1,291 @@
1+//
2+// FirstStepView.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 15/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+protocol MapUpdater: class {
12+ func update(_ date: Date)
13+}
14+
15+class FirstStepView: UIView {
16+
17+ weak var mapUpdater: MapUpdater?
18+
19+ var chosenPoint: Int? {
20+ didSet {
21+ guard
22+ let periods = chosenPoint,
23+ let dateInt = date,
24+ let newDate = Date.getDateFromCurrent(days: dateInt, periods: periods)
25+ else { return }
26+ fullDate = newDate
27+ }
28+ }
29+
30+ var fullDate: Date? {
31+ didSet {
32+ guard let date = fullDate, let _ = chosenPoint else { return }
33+
34+ let (prev, curr, next) = date.getPrevCurrentNextMonth()
35+ setupMonth(prev, curr, next)
36+
37+ mapUpdater?.update(date)
38+ }
39+ }
40+
41+ var date: Int? {
42+ didSet {
43+ guard
44+ let dateInt = date,
45+ let periods = chosenPoint,
46+ let newDate = Date.getDateFromCurrent(days: dateInt, periods: periods)
47+ else { return }
48+ fullDate = newDate
49+
50+ guard
51+ let date = fullDate?.getDMY()
52+ else { return }
53+
54+ let bookings = HFunc.main.filterPeriodsInDate(bookingsForDates, date)
55+ setUpBookingsForIntervals(reservations: bookings)
56+ }
57+ }
58+
59+ var bookingsForDates: [ReservationPeriod] = [] {
60+ didSet {
61+ guard
62+ let date = fullDate?.getDMY()
63+ else { return }
64+
65+ let bookings = HFunc.main.filterPeriodsInDate(bookingsForDates, date)
66+
67+ setUpBookingsForIntervals(reservations: bookings)
68+ }
69+ }
70+
71+ // intervals
72+
73+ @IBOutlet weak var scrollViewIntervals: UIScrollView!
74+
75+ @IBOutlet weak var stackViewIntervals: UIStackView!
76+
77+ // dates
78+
79+ @IBOutlet weak var datesStackView: UIStackView!
80+
81+ @IBOutlet weak var datesScrollView: UIScrollView!
82+
83+ // note labels
84+
85+ @IBOutlet weak var earlierThan12Label: UILabel!
86+
87+ @IBOutlet weak var laterThan3Label: UILabel!
88+
89+ // months
90+
91+ @IBOutlet weak var previousMonthLabel: UILabel!
92+
93+ @IBOutlet weak var currentMonthLabel: UILabel!
94+
95+ @IBOutlet weak var nextMonthLabel: UILabel!
96+
97+
98+ var bookingsViewsForDate: [UIView] = []
99+
100+
101+ override func awakeFromNib() {
102+ super.awakeFromNib()
103+
104+ scrollViewIntervals.delegate = self
105+ datesScrollView.delegate = self
106+
107+ scrollViewIntervals.showsHorizontalScrollIndicator = false
108+ datesScrollView.showsHorizontalScrollIndicator = false
109+
110+ setUpDateStackView()
111+ setUpIntervalStackView()
112+ }
113+
114+ func setUpIntervalStackView() {
115+
116+ for period in 0...Constants.day10MinPeriods {
117+
118+ let timePointView = TimePointView.loadFromNib()
119+ timePointView?.setUp(withTimePoint: period)
120+ let view = UIView(frame: CGRect(x: 0, y: 0, width: 35, height: 92))
121+ view.addSubviewThatFills(timePointView)
122+ stackViewIntervals.addArrangedSubview(view)
123+ }
124+
125+ setupClosingInterval()
126+ }
127+
128+ /// Вьюшка, обозначающая часы закрытия кальянки
129+ func setupClosingInterval() {
130+ let offset = CGFloat(Constants.startClosingTime * Constants.widthTimePoint + Constants.widthTimePoint / 2)
131+ let width = CGFloat(Constants.closingDuration * Constants.widthTimePoint)
132+ let height = CGFloat(Constants.heightIntervals)
133+ let closingTimeView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: height))
134+ closingTimeView.translatesAutoresizingMaskIntoConstraints = false
135+ scrollViewIntervals.addSubview(closingTimeView)
136+ closingTimeView.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.5)
137+
138+ NSLayoutConstraint.activate([
139+ closingTimeView.leftAnchor.constraint(equalTo: scrollViewIntervals.leftAnchor, constant: offset),
140+ closingTimeView.bottomAnchor.constraint(equalToSystemSpacingBelow: scrollViewIntervals.bottomAnchor, multiplier: 0),
141+ closingTimeView.heightAnchor.constraint(equalToConstant: height),
142+ closingTimeView.widthAnchor.constraint(equalToConstant: width)
143+ ])
144+ }
145+
146+ func setUpBookingsForIntervals(reservations: [ReservationPeriod]) {
147+ bookingsViewsForDate.forEach { $0.removeFromSuperview() }
148+ bookingsViewsForDate = []
149+
150+ for reservation in reservations {
151+ let uiview = UIView(frame: CGRect(x: 0, y: 0, width: Constants.widthTimePoint * reservation.duration, height: Constants.heightIntervals))
152+ uiview.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.5)
153+
154+
155+ uiview.translatesAutoresizingMaskIntoConstraints = false
156+ scrollViewIntervals.addSubview(uiview)
157+
158+ guard let date = date else { return }
159+ let startDate = Date.getDateFromCurrent(days: date)!.set(hours: 0, minutes: 0, seconds: 0)!
160+
161+ let s = reservation.startTime.getMinutesPeriods(fromStart: startDate) * Constants.widthTimePoint
162+ let d = reservation.duration * Constants.widthTimePoint
163+
164+ let startTime = s < 0 ? 0 : s
165+ var duration = 0
166+ if s < 0 {
167+ duration = reservation.endTime.getMinutesPeriods(fromStart: startDate) * Constants.widthTimePoint
168+ } else {
169+ duration = (s + d) > Constants.widthOfIntervals ? Constants.widthOfIntervals - s : d
170+ }
171+
172+ NSLayoutConstraint.activate([
173+ uiview.bottomAnchor.constraint(equalToSystemSpacingBelow: scrollViewIntervals.bottomAnchor, multiplier: 0),
174+ uiview.leftAnchor.constraint(equalTo: scrollViewIntervals.leftAnchor,
175+ constant: CGFloat(Constants.widthTimePoint / 2 + startTime)),
176+ uiview.widthAnchor.constraint(equalToConstant: CGFloat(duration)),
177+ uiview.heightAnchor.constraint(equalToConstant: CGFloat(Constants.heightIntervals))
178+ ])
179+
180+ bookingsViewsForDate.append(uiview)
181+ }
182+ }
183+
184+ func setContent() {
185+ scrollViewIntervals.contentSize = stackViewIntervals.frame.size
186+ datesScrollView.contentSize = datesStackView.frame.size
187+
188+ let halfWidth = frame.size.width / 2
189+ let edges = UIEdgeInsets(top: 0, left: halfWidth, bottom: 0, right: halfWidth)
190+
191+ scrollViewIntervals.contentInset = edges
192+ datesScrollView.contentInset = edges
193+
194+ datesScrollView.setContentOffset(CGPoint(x: abs(Constants.widthDate * Constants.daysCount / 2 - Int(edges.left)) + 8, y: 0),
195+ animated: true)
196+ scrollViewIntervals.setContentOffset(CGPoint(x: abs(Constants.widthTimePoint * Constants.day10MinPeriods / 2 - Int(edges.left)) + 7, y: 0),
197+ animated: true)
198+ }
199+
200+
201+ /// Method for setting up `stackViewIntervals` with appropriate busy intervals of chosen table
202+ /// - Parameter data: Map of booked periods by key - date - is provided
203+ func setUp(_ data: [ReservationPeriod]) {
204+ bookingsForDates = data
205+ }
206+
207+ func setUpDateStackView() {
208+ let dates = Date.getNext(days: Constants.daysCount)
209+
210+ for date in dates {
211+ let dateView = DateView.loadFromNib()
212+ dateView?.setUp(with: date)
213+ let view = UIView(frame: CGRect(x: 0, y: 0, width: 21, height: 59))
214+ view.addSubviewThatFills(dateView)
215+ datesStackView.addArrangedSubview(view)
216+ }
217+ }
218+
219+ func setupMonth(_ prev: String, _ curr: String, _ next: String) {
220+ currentMonthLabel.text = curr
221+ previousMonthLabel.text = prev
222+ nextMonthLabel.text = next
223+ }
224+}
225+
226+extension FirstStepView: UIScrollViewDelegate {
227+
228+
229+ func scrollViewDidScroll(_ scrollView: UIScrollView) {
230+
231+ if scrollView == scrollViewIntervals {
232+ intervalsDidScroll()
233+ } else {
234+ datesDidScroll()
235+ }
236+ }
237+
238+ func intervalsDidScroll() {
239+ let inset = scrollViewIntervals.contentInset.left
240+ let alpha12 = 1 / (abs(inset + scrollViewIntervals.contentOffset.x) / inset)
241+ let alpha3 = 1 / (abs(inset + scrollViewIntervals.contentOffset.x - stackViewIntervals.frame.width) / inset)
242+
243+ earlierThan12Label.textColor = earlierThan12Label.textColor.withAlphaComponent(alpha12)
244+ laterThan3Label.textColor = laterThan3Label.textColor.withAlphaComponent(alpha3)
245+
246+ for (index, stack) in stackViewIntervals.subviews.enumerated() {
247+ if let intervalStack = stack.subviews[0] as? TimePointView {
248+ let positionToSelf = intervalStack.convert(intervalStack.frame, to: self)
249+
250+ if abs((positionToSelf.minX + positionToSelf.maxX) / 2 - frame.size.width / 2) < 5.5
251+ {
252+ intervalStack.timePoint.backgroundColor = .darkGray
253+ chosenPoint = index
254+ } else {
255+ intervalStack.timePoint.backgroundColor = .lightGray
256+ }
257+ }
258+ }
259+ }
260+
261+ func datesDidScroll() {
262+ for (_, stack) in datesStackView.subviews.enumerated() {
263+ if let dateView = stack.subviews[0] as? DateView {
264+ let positionToSelf = dateView.convert(dateView.frame, to: self)
265+
266+ if abs((positionToSelf.minX + positionToSelf.maxX) / 2 - frame.size.width / 2) < 15.5 {
267+ dateView.dateLabel.textColor = .black
268+ date = Int(datesScrollView.contentInset.left + datesScrollView.contentOffset.x) / 31
269+ } else {
270+ dateView.dateLabel.textColor = .lightGray
271+ }
272+ }
273+ }
274+ }
275+}
276+
277+// MARK: - Nested types
278+
279+extension FirstStepView {
280+ enum Constants {
281+ /// 24 ч * 60 минут / 10 минут в периоде; [00:00 ... 23:50]
282+ static let day10MinPeriods = 143
283+ static let daysCount = 14
284+ static let widthTimePoint = 11
285+ static let widthDate = 31
286+ static let heightIntervals = 70
287+ static let closingDuration = 54
288+ static let startClosingTime = 18
289+ static let widthOfIntervals = 1573
290+ }
291+}
Hookah Tau/Controllers/Client/Reservations/Steps/1/FirstStepView.xibnew file+250
@@ -0,0 +1,250 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina4_7" orientation="portrait" appearance="light"/>
4+ <dependencies>
5+ <deployment identifier="iOS"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8+ <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
9+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10+ </dependencies>
11+ <objects>
12+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
13+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
14+ <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="FirstStepView" customModule="Hookah_Tau" customModuleProvider="target">
15+ <rect key="frame" x="0.0" y="0.0" width="414" height="225"/>
16+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
17+ <subviews>
18+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pgz-8G-Kx4" userLabel="Under scroll dates">
19+ <rect key="frame" x="0.0" y="29" width="414" height="59"/>
20+ <subviews>
21+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ocm-Ba-WCp">
22+ <rect key="frame" x="0.0" y="0.0" width="414" height="1"/>
23+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
24+ <constraints>
25+ <constraint firstAttribute="height" constant="1" id="Gst-4x-W6O"/>
26+ </constraints>
27+ </view>
28+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Eb3-64-oGl">
29+ <rect key="frame" x="0.0" y="58" width="414" height="1"/>
30+ <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
31+ <constraints>
32+ <constraint firstAttribute="height" constant="1" id="Llo-E4-www"/>
33+ </constraints>
34+ </view>
35+ </subviews>
36+ <color key="backgroundColor" red="0.8901960784313725" green="0.8901960784313725" blue="0.8901960784313725" alpha="0.14999999999999999" colorSpace="custom" customColorSpace="calibratedRGB"/>
37+ <constraints>
38+ <constraint firstItem="Ocm-Ba-WCp" firstAttribute="leading" secondItem="pgz-8G-Kx4" secondAttribute="leading" id="AyK-U9-Htr"/>
39+ <constraint firstAttribute="trailing" secondItem="Eb3-64-oGl" secondAttribute="trailing" id="UWJ-H4-iVD"/>
40+ <constraint firstItem="Eb3-64-oGl" firstAttribute="leading" secondItem="pgz-8G-Kx4" secondAttribute="leading" id="UqX-3l-90O"/>
41+ <constraint firstAttribute="trailing" secondItem="Ocm-Ba-WCp" secondAttribute="trailing" id="drj-rX-UvL"/>
42+ <constraint firstAttribute="bottom" secondItem="Eb3-64-oGl" secondAttribute="bottom" id="ebx-vE-0aF"/>
43+ <constraint firstItem="Ocm-Ba-WCp" firstAttribute="top" secondItem="pgz-8G-Kx4" secondAttribute="top" id="nEC-cm-sIz"/>
44+ </constraints>
45+ </view>
46+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="954-g3-FZD" userLabel="Under scroll view">
47+ <rect key="frame" x="0.0" y="97" width="414" height="91"/>
48+ <subviews>
49+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dh5-kt-LFH">
50+ <rect key="frame" x="0.0" y="21" width="414" height="70"/>
51+ <subviews>
52+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nqq-Xp-Lig">
53+ <rect key="frame" x="0.0" y="0.0" width="414" height="1"/>
54+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
55+ <constraints>
56+ <constraint firstAttribute="height" constant="1" id="me1-hs-aWn"/>
57+ </constraints>
58+ </view>
59+ <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="kS7-N4-kdg">
60+ <rect key="frame" x="16" y="9" width="382" height="52"/>
61+ <subviews>
62+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Для брони времени раньше 12:00 свяжитесь с администратором" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6DK-77-Npa">
63+ <rect key="frame" x="0.0" y="0.0" width="187" height="52"/>
64+ <fontDescription key="fontDescription" type="system" pointSize="13"/>
65+ <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
66+ <nil key="highlightedColor"/>
67+ </label>
68+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Для брони времени позже 3:00 свяжитесь с администратором" textAlignment="right" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qz5-ce-S3I">
69+ <rect key="frame" x="195" y="0.0" width="187" height="52"/>
70+ <fontDescription key="fontDescription" type="system" pointSize="13"/>
71+ <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
72+ <nil key="highlightedColor"/>
73+ </label>
74+ </subviews>
75+ </stackView>
76+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zqK-OT-P26">
77+ <rect key="frame" x="0.0" y="69" width="414" height="1"/>
78+ <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
79+ <constraints>
80+ <constraint firstAttribute="height" constant="1" id="iUR-sJ-1M1"/>
81+ <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="1" id="xeo-B1-TLL"/>
82+ </constraints>
83+ </view>
84+ </subviews>
85+ <color key="backgroundColor" red="0.8901960784313725" green="0.8901960784313725" blue="0.8901960784313725" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
86+ <constraints>
87+ <constraint firstItem="nqq-Xp-Lig" firstAttribute="top" secondItem="dh5-kt-LFH" secondAttribute="top" id="6xZ-TR-tvC"/>
88+ <constraint firstAttribute="trailing" secondItem="zqK-OT-P26" secondAttribute="trailing" id="SeY-dj-8cT"/>
89+ <constraint firstAttribute="trailing" secondItem="nqq-Xp-Lig" secondAttribute="trailing" id="XtL-jd-AZH"/>
90+ <constraint firstItem="kS7-N4-kdg" firstAttribute="leading" secondItem="dh5-kt-LFH" secondAttribute="leading" constant="16" id="d0b-bx-btq"/>
91+ <constraint firstItem="zqK-OT-P26" firstAttribute="top" secondItem="kS7-N4-kdg" secondAttribute="bottom" constant="8" id="eNz-f4-nlO"/>
92+ <constraint firstAttribute="bottom" secondItem="zqK-OT-P26" secondAttribute="bottom" id="m0O-4r-wfZ"/>
93+ <constraint firstItem="kS7-N4-kdg" firstAttribute="top" secondItem="nqq-Xp-Lig" secondAttribute="bottom" constant="8" id="o6k-wD-gGp"/>
94+ <constraint firstAttribute="trailing" secondItem="kS7-N4-kdg" secondAttribute="trailing" constant="16" id="qfN-XY-Uqq"/>
95+ <constraint firstItem="nqq-Xp-Lig" firstAttribute="leading" secondItem="dh5-kt-LFH" secondAttribute="leading" id="qr9-52-TNC"/>
96+ <constraint firstAttribute="height" constant="70" id="tcS-2U-ecA"/>
97+ <constraint firstItem="zqK-OT-P26" firstAttribute="leading" secondItem="dh5-kt-LFH" secondAttribute="leading" id="yUf-Cj-HmN"/>
98+ </constraints>
99+ </view>
100+ </subviews>
101+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
102+ <constraints>
103+ <constraint firstAttribute="trailing" secondItem="dh5-kt-LFH" secondAttribute="trailing" id="Ogq-Ny-UtZ"/>
104+ <constraint firstItem="dh5-kt-LFH" firstAttribute="leading" secondItem="954-g3-FZD" secondAttribute="leading" id="aGL-6Q-gwb"/>
105+ <constraint firstAttribute="bottom" secondItem="dh5-kt-LFH" secondAttribute="bottom" id="sCl-ct-Awr"/>
106+ </constraints>
107+ </view>
108+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="TriangleDown" translatesAutoresizingMaskIntoConstraints="NO" id="5dC-Lq-opV">
109+ <rect key="frame" x="184.5" y="0.0" width="45" height="29"/>
110+ <constraints>
111+ <constraint firstAttribute="width" constant="45" id="Tsw-fS-8qs"/>
112+ <constraint firstAttribute="height" constant="29" id="YWD-ja-gD5"/>
113+ </constraints>
114+ </imageView>
115+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="TriangleUp" translatesAutoresizingMaskIntoConstraints="NO" id="Igw-O9-W92">
116+ <rect key="frame" x="184.5" y="196" width="45" height="29"/>
117+ <constraints>
118+ <constraint firstAttribute="height" constant="29" id="AdE-yJ-WLL"/>
119+ <constraint firstAttribute="width" constant="45" id="Eaa-P8-3mv"/>
120+ </constraints>
121+ </imageView>
122+ <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a6N-9A-8y5">
123+ <rect key="frame" x="0.0" y="97" width="414" height="91"/>
124+ <subviews>
125+ <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="z9p-OK-tL7">
126+ <rect key="frame" x="0.0" y="0.0" width="414" height="91"/>
127+ </stackView>
128+ </subviews>
129+ <constraints>
130+ <constraint firstItem="z9p-OK-tL7" firstAttribute="leading" secondItem="a6N-9A-8y5" secondAttribute="leading" id="66I-Xl-dE9"/>
131+ <constraint firstItem="z9p-OK-tL7" firstAttribute="width" secondItem="a6N-9A-8y5" secondAttribute="width" priority="250" id="8CZ-Pa-ROG"/>
132+ <constraint firstAttribute="bottom" secondItem="z9p-OK-tL7" secondAttribute="bottom" id="Bve-Ls-KhA"/>
133+ <constraint firstItem="z9p-OK-tL7" firstAttribute="top" secondItem="a6N-9A-8y5" secondAttribute="top" id="Qys-Ws-joK"/>
134+ <constraint firstItem="z9p-OK-tL7" firstAttribute="height" secondItem="a6N-9A-8y5" secondAttribute="height" id="a5D-0u-zAW"/>
135+ <constraint firstAttribute="trailing" secondItem="z9p-OK-tL7" secondAttribute="trailing" id="riY-nE-EUp"/>
136+ </constraints>
137+ <viewLayoutGuide key="contentLayoutGuide" id="Y0a-LG-dJH"/>
138+ <viewLayoutGuide key="frameLayoutGuide" id="bsE-qj-8ef"/>
139+ </scrollView>
140+ <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Y9G-UI-WV7">
141+ <rect key="frame" x="0.0" y="29" width="414" height="59"/>
142+ <subviews>
143+ <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="52e-LM-cF6">
144+ <rect key="frame" x="0.0" y="0.0" width="414" height="59"/>
145+ </stackView>
146+ </subviews>
147+ <constraints>
148+ <constraint firstItem="52e-LM-cF6" firstAttribute="height" secondItem="Y9G-UI-WV7" secondAttribute="height" id="2wC-n3-oG9"/>
149+ <constraint firstItem="52e-LM-cF6" firstAttribute="leading" secondItem="Y9G-UI-WV7" secondAttribute="leading" id="GZW-kT-OtX"/>
150+ <constraint firstItem="52e-LM-cF6" firstAttribute="width" secondItem="Y9G-UI-WV7" secondAttribute="width" priority="250" id="Lb4-nJ-yt6"/>
151+ <constraint firstAttribute="trailing" secondItem="52e-LM-cF6" secondAttribute="trailing" id="edz-yx-1Bj"/>
152+ <constraint firstAttribute="bottom" secondItem="52e-LM-cF6" secondAttribute="bottom" id="qNo-Pi-gV4"/>
153+ <constraint firstItem="52e-LM-cF6" firstAttribute="top" secondItem="Y9G-UI-WV7" secondAttribute="top" id="wNf-Sa-CrY"/>
154+ </constraints>
155+ <viewLayoutGuide key="contentLayoutGuide" id="uZM-JL-J3w"/>
156+ <viewLayoutGuide key="frameLayoutGuide" id="dbW-UW-YAk"/>
157+ </scrollView>
158+ <view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fvt-zf-8tU" customClass="RadialGradientView" customModule="Hookah_Tau" customModuleProvider="target">
159+ <rect key="frame" x="0.0" y="29" width="414" height="59"/>
160+ <subviews>
161+ <stackView opaque="NO" contentMode="scaleToFill" distribution="equalSpacing" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="OEF-Kc-d38">
162+ <rect key="frame" x="8" y="5" width="398" height="14.5"/>
163+ <subviews>
164+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="November" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Mn-Mn-qaI">
165+ <rect key="frame" x="0.0" y="0.0" width="58.5" height="14.5"/>
166+ <fontDescription key="fontDescription" type="system" pointSize="12"/>
167+ <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
168+ <nil key="highlightedColor"/>
169+ </label>
170+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="January" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rfg-Ts-DX0">
171+ <rect key="frame" x="353" y="0.0" width="45" height="14.5"/>
172+ <fontDescription key="fontDescription" type="system" pointSize="12"/>
173+ <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
174+ <nil key="highlightedColor"/>
175+ </label>
176+ </subviews>
177+ </stackView>
178+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="December" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fbc-VX-43f">
179+ <rect key="frame" x="176.5" y="5" width="61" height="14.5"/>
180+ <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="12"/>
181+ <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
182+ <nil key="highlightedColor"/>
183+ </label>
184+ </subviews>
185+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
186+ <constraints>
187+ <constraint firstAttribute="trailing" secondItem="OEF-Kc-d38" secondAttribute="trailing" constant="8" id="BKe-IX-uiY"/>
188+ <constraint firstItem="OEF-Kc-d38" firstAttribute="leading" secondItem="fvt-zf-8tU" secondAttribute="leading" constant="8" id="Cc6-Iv-RT8"/>
189+ <constraint firstItem="Fbc-VX-43f" firstAttribute="top" secondItem="fvt-zf-8tU" secondAttribute="top" constant="5" id="jj2-kv-wnF"/>
190+ <constraint firstItem="OEF-Kc-d38" firstAttribute="top" secondItem="fvt-zf-8tU" secondAttribute="top" constant="5" id="pmQ-MG-28r"/>
191+ <constraint firstItem="Fbc-VX-43f" firstAttribute="centerX" secondItem="fvt-zf-8tU" secondAttribute="centerX" id="wAj-Z8-AP0"/>
192+ </constraints>
193+ <userDefinedRuntimeAttributes>
194+ <userDefinedRuntimeAttribute type="color" keyPath="outsideColor">
195+ <color key="value" white="1" alpha="0.88409674657534243" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
196+ </userDefinedRuntimeAttribute>
197+ <userDefinedRuntimeAttribute type="color" keyPath="insideColor">
198+ <color key="value" white="0.67000000000000004" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
199+ </userDefinedRuntimeAttribute>
200+ </userDefinedRuntimeAttributes>
201+ </view>
202+ </subviews>
203+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
204+ <constraints>
205+ <constraint firstItem="Y9G-UI-WV7" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="22z-Ck-vsZ"/>
206+ <constraint firstItem="a6N-9A-8y5" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="5c8-YB-dSB"/>
207+ <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="954-g3-FZD" secondAttribute="bottom" constant="37" id="C3k-Mb-wT4"/>
208+ <constraint firstItem="Y9G-UI-WV7" firstAttribute="top" secondItem="5dC-Lq-opV" secondAttribute="bottom" id="E97-Lg-K2s"/>
209+ <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="fvt-zf-8tU" secondAttribute="trailing" id="Eeh-zB-KWe"/>
210+ <constraint firstItem="a6N-9A-8y5" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="F03-yv-41V"/>
211+ <constraint firstItem="pgz-8G-Kx4" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="G0y-2f-SkS"/>
212+ <constraint firstItem="5dC-Lq-opV" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="If5-v7-UAj"/>
213+ <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="pgz-8G-Kx4" secondAttribute="bottom" constant="137" id="Lgn-Nv-wjD"/>
214+ <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="954-g3-FZD" secondAttribute="trailing" id="MGt-d4-Win"/>
215+ <constraint firstItem="fvt-zf-8tU" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="SaI-rP-2em"/>
216+ <constraint firstItem="Igw-O9-W92" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="TtM-Bc-V1U"/>
217+ <constraint firstItem="Igw-O9-W92" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="V9u-Eu-VME"/>
218+ <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="pgz-8G-Kx4" secondAttribute="trailing" id="Z6D-PY-Jrh"/>
219+ <constraint firstItem="Igw-O9-W92" firstAttribute="top" secondItem="a6N-9A-8y5" secondAttribute="bottom" constant="8" id="f4D-nq-HMa"/>
220+ <constraint firstItem="Y9G-UI-WV7" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="gZw-8a-dTG"/>
221+ <constraint firstItem="954-g3-FZD" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="itw-0z-3i7"/>
222+ <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="fvt-zf-8tU" secondAttribute="bottom" constant="137" id="lOx-ke-O6a"/>
223+ <constraint firstItem="z9p-OK-tL7" firstAttribute="top" secondItem="52e-LM-cF6" secondAttribute="bottom" constant="9" id="ldj-Qh-p0k"/>
224+ <constraint firstItem="fvt-zf-8tU" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="29" id="pSg-dd-INI"/>
225+ <constraint firstItem="pgz-8G-Kx4" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="29" id="vfO-LG-tqR"/>
226+ <constraint firstItem="954-g3-FZD" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="97" id="vhK-2E-j3k"/>
227+ <constraint firstItem="5dC-Lq-opV" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="xOt-l0-Vzy"/>
228+ <constraint firstItem="a6N-9A-8y5" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="97" id="yyf-QB-vfF"/>
229+ </constraints>
230+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
231+ <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
232+ <connections>
233+ <outlet property="currentMonthLabel" destination="Fbc-VX-43f" id="CJr-eH-QMp"/>
234+ <outlet property="datesScrollView" destination="Y9G-UI-WV7" id="dbT-BM-Ckq"/>
235+ <outlet property="datesStackView" destination="52e-LM-cF6" id="6Ni-IN-sm4"/>
236+ <outlet property="earlierThan12Label" destination="6DK-77-Npa" id="ftP-Jz-gzw"/>
237+ <outlet property="laterThan3Label" destination="qz5-ce-S3I" id="dzR-7k-uDq"/>
238+ <outlet property="nextMonthLabel" destination="Rfg-Ts-DX0" id="rpk-ci-pzX"/>
239+ <outlet property="previousMonthLabel" destination="5Mn-Mn-qaI" id="c0S-Yz-e83"/>
240+ <outlet property="scrollViewIntervals" destination="a6N-9A-8y5" id="uDW-QY-gNF"/>
241+ <outlet property="stackViewIntervals" destination="z9p-OK-tL7" id="0Mj-wX-kq7"/>
242+ </connections>
243+ <point key="canvasLocation" x="-110.40000000000001" y="63.418290854572717"/>
244+ </view>
245+ </objects>
246+ <resources>
247+ <image name="TriangleDown" width="40" height="41"/>
248+ <image name="TriangleUp" width="40" height="41"/>
249+ </resources>
250+</document>
Hookah Tau/Controllers/Client/Reservations/Steps/2/SecondStepReservationCoordinator.swiftnew file+62
@@ -0,0 +1,62 @@
1+//
2+// SecondStepReservationCoordinator.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 21/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+
12+class SecondStepReservationCoordinator: BaseCoordinator {
13+
14+ // MARK: - Properties
15+
16+ var didFinish: (() -> Void)?
17+
18+ var goBack: ((MapImageScroll?) -> Void)?
19+
20+ var model: SecondStepModel?
21+
22+ var mapView: MapImageScroll?
23+
24+ var onBooking: ((MapImageScroll, Reservation) -> Void)?
25+
26+ var vc: SecondStepReservationViewController?
27+
28+ // MARK: - Lifecycle
29+
30+ override func start() {
31+ let storyboard = UIStoryboard(name: "Reservation", bundle: nil)
32+ vc = storyboard.instantiateViewController(withIdentifier: "SecondStepReservationViewController") as? SecondStepReservationViewController
33+
34+ guard let viewController = vc else { return }
35+
36+ viewController.model = model
37+ viewController.mapView = mapView
38+ viewController.coordinator = self
39+
40+ navigationController?.pushViewController(viewController, animated: false)
41+ }
42+
43+ func cancel(_ mapView: MapImageScroll?) {
44+ goBack?(mapView)
45+ }
46+
47+ func book(_ mapView: MapImageScroll?, reservation: Reservation) {
48+ let coordinator = ThirdStepReservationCoordinator(navigationController: navigationController)
49+ addDependency(coordinator)
50+
51+ coordinator.didFinish = { [weak self] in
52+ self?.navigationController?.popViewController(animated: false)
53+ self?.removeDependency(coordinator)
54+ self?.didFinish?()
55+ }
56+
57+ coordinator.mapView = mapView
58+ coordinator.resrvation = reservation
59+
60+ coordinator.start()
61+ }
62+}
Hookah Tau/Controllers/Client/Reservations/Steps/2/SecondStepReservationViewController.swiftnew file+142
@@ -0,0 +1,142 @@
1+//
2+// SecondStepReservationViewController.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 21/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class SecondStepReservationViewController: BaseViewController {
12+
13+ // MARK: - Properties
14+
15+ @IBOutlet weak var childContentView: UIView!
16+
17+ var secondStepView: SecondStepView?
18+
19+ /// координатор
20+ weak var coordinator: SecondStepReservationCoordinator?
21+
22+ /// service для создания бронирования
23+ var reservationService: ReservationsService?
24+
25+ /// map view from the previous screen
26+ var mapView: MapImageScroll?
27+
28+ var model: SecondStepModel?
29+
30+ /// address of the building to display in nav bar title
31+ var address: String = "Покровский бр., 11"
32+
33+ let confirmButton: Button = {
34+ let button = Button()
35+ let style = BlackButtonStyle()
36+ style.apply(to: button, withTitle: "ПОДТВЕРДИТЬ")
37+ return button
38+ }()
39+
40+ let cancelButton: Button = {
41+ let button = Button()
42+ let style = BlackButtonStyle()
43+ style.apply(to: button, withTitle: "ОТМЕНИТЬ")
44+ return button
45+ }()
46+
47+ // MARK: - Lifecycle
48+
49+ override func viewDidLoad() {
50+ super.viewDidLoad()
51+
52+ setupNavBar()
53+ setupMap()
54+ setupChildContainer()
55+ setupButtons()
56+
57+ reservationService = ReservationsService(apiClient: APIClient.shared)
58+ }
59+
60+ override func viewWillAppear(_ animated: Bool) {
61+ super.viewWillAppear(animated)
62+
63+ tabBarController?.tabBar.isHidden = true
64+ }
65+
66+
67+ // MARK: - Setup
68+
69+ func setupNavBar() {
70+ navigationItem.hidesBackButton = true
71+ navigationItem.title = address
72+ }
73+
74+ func setupChildContainer() {
75+
76+ secondStepView = SecondStepView.loadFromNib()
77+ childContentView.addSubviewThatFills(secondStepView)
78+ guard let model = model else { return }
79+ secondStepView?.bind(model: model)
80+ }
81+
82+ func setupMap() {
83+ guard let map = mapView else { return }
84+ view.addSubview(map)
85+
86+ NSLayoutConstraint.activate([
87+ map.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0),
88+ map.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
89+ map.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
90+ map.bottomAnchor.constraint(equalTo: childContentView.topAnchor, constant: 0)
91+ ])
92+
93+ let width = view.frame.width
94+
95+ mapView?.scrollViewParent.setContentOffset(CGPoint(x: 0, y: -100), animated: false)
96+ mapView?.scrollViewParent.contentInset = UIEdgeInsets(top: 100,
97+ left: width / 2,
98+ bottom: 100,
99+ right: width / 2)
100+ mapView?.isUserInteractionEnabled = false
101+ view.sendSubviewToBack(map)
102+ }
103+
104+ override func viewDidAppear(_ animated: Bool) {
105+ super.viewDidAppear(animated)
106+
107+ mapView?.scrollToTable(table: model?.table ?? 0)
108+ }
109+
110+ func setupButtons() {
111+ addStackViewWithButtons(leftBtn: cancelButton,
112+ rightBtn: confirmButton,
113+ constant: -childContentView.frame.height - 20)
114+ cancelButton.addTarget(self, action: #selector(cancelChange), for: .touchUpInside)
115+ confirmButton.addTarget(self, action: #selector(book), for: .touchUpInside)
116+ }
117+
118+ // MARK: - Button handlers
119+
120+ @objc func cancelChange() {
121+ coordinator?.cancel(mapView)
122+ }
123+
124+ @objc func book() {
125+ guard let booking = secondStepView?.data else { return }
126+ confirmButton.loading = true
127+
128+ print(booking)
129+
130+ reservationService?.createReservation(data: booking, completion: { [weak self] (result) in
131+ switch result {
132+ case .failure:
133+ self?.displayAlert(with: "Не удалось совершить бронирование :(")
134+
135+ case .success(let reservation):
136+ self?.coordinator?.book(self?.mapView, reservation: reservation)
137+ }
138+
139+ self?.confirmButton.loading = false
140+ })
141+ }
142+}
Hookah Tau/Controllers/Client/Reservations/Steps/2/SecondStepView.swiftnew file+358
@@ -0,0 +1,358 @@
1+//
2+// SecondStepView.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 21/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+/// стол, начало, интервалы (???), establishment
12+struct SecondStepModel {
13+ var establishment: Int
14+ var table: Int
15+ var startTime: Date
16+ var endTime: Date? = nil
17+ var reservedintervals: [ReservationPeriod]
18+}
19+
20+class SecondStepView: UIView {
21+
22+ // MARK: - IBAOutlets
23+
24+ @IBOutlet weak var totalBookingLabel: UILabel!
25+
26+ @IBOutlet weak var infoLabel: UILabel!
27+
28+ @IBOutlet weak var specialLabel: UILabel! {
29+ didSet {
30+ let m = NSMutableAttributedString(string: "Если Вам нужно что-то особенное, Вы можете связаться с администратором ")
31+
32+ let image1Attachment = NSTextAttachment()
33+ image1Attachment.bounds = CGRect(x: 0, y: -3, width: 15, height: 15)
34+ image1Attachment.image = #imageLiteral(resourceName: "phone")
35+ let image1String = NSMutableAttributedString(attachment: image1Attachment)
36+ m.append(image1String)
37+ specialLabel.attributedText = m
38+
39+ let gr = UITapGestureRecognizer(target: self, action: #selector(callAlmin))
40+ specialLabel.addGestureRecognizer(gr)
41+ }
42+ }
43+
44+
45+ @IBOutlet weak var numberOfGuestsLabel: UILabel!
46+
47+ @IBOutlet weak var guestSlider: UISlider!
48+
49+ @IBOutlet weak var scrollView: UIScrollView!
50+
51+ @IBOutlet weak var intervalsStackView: UIStackView!
52+
53+ // MARK: - Peoperties
54+
55+ /// Время начала вертелки.
56+ /// Для клиента это 12:00 смены (надо вызвать метод для получения текущей смены).
57+ /// Для администратора это `t` - 24h
58+ var startDate: Date?
59+
60+ /// Модель вьюшки
61+ var data: ReservationData? {
62+ didSet {
63+ guard let d = data else { return }
64+ let (date, time) = Date.format(d.startTime, d.endTime)
65+ totalBookingLabel.text = "Забронировать \(d.reservedTable) столик на \(d.numberOfGuests) человека \(date) \(time)?"
66+ }
67+ }
68+
69+ /// Модель с которой мы приходим в эту вьюшку
70+ var model: SecondStepModel? {
71+ didSet {
72+ guard let model = model else { return }
73+
74+ data = ReservationData(establishment: model.establishment,
75+ startTime: model.startTime,
76+ endTime: model.endTime ?? model.startTime.addHours(2),
77+ numberOfGuests: Int(guestSlider.value),
78+ reservedTable: model.table)
79+
80+ // isAdmin
81+ let isAdmin = DataStorage.standard.getUserModel()?.isAdmin ?? false
82+
83+ let (start, _) = isAdmin ? model.startTime.getAdminStartingAndEndPoint() : model.startTime.getClientStartingAndEndPoint()
84+
85+ startDate = start
86+
87+ setUpIntervals(isAdmin)
88+ setUpReservedIntervals(model.reservedintervals, isAdmin)
89+ setUpBookingPeriod(model.startTime, model.endTime)
90+ }
91+ }
92+
93+ // констрейнты начала и конца интервала
94+ var startLeadingConstraint: NSLayoutConstraint!
95+ var endLeadingConstraint: NSLayoutConstraint!
96+
97+ var startPoint: UIImageView = {
98+ var view = UIImageView()
99+ view.isUserInteractionEnabled = true
100+ view.image = #imageLiteral(resourceName: "handle_left")
101+ view.translatesAutoresizingMaskIntoConstraints = false
102+ return view
103+ }()
104+
105+ var endPoint: UIImageView = {
106+ var view = UIImageView()
107+ view.isUserInteractionEnabled = true
108+ view.image = #imageLiteral(resourceName: "Group")
109+ view.translatesAutoresizingMaskIntoConstraints = false
110+ return view
111+ }()
112+
113+ /// Интервал
114+ var fillInterval: UIView = {
115+ var view = UIView()
116+ view.backgroundColor = #colorLiteral(red: 0, green: 0.5921568627, blue: 1, alpha: 0.3426262843)
117+ view.translatesAutoresizingMaskIntoConstraints = false
118+ return view
119+ }()
120+
121+ // MARK: - Lifecycle
122+
123+ override func awakeFromNib() {
124+ super.awakeFromNib()
125+
126+ scrollView.delegate = self
127+
128+ scrollView.showsHorizontalScrollIndicator = false
129+ }
130+
131+ @IBAction func sliderValueChanged(_ sender: UISlider) {
132+ let value = Int(sender.value)
133+ numberOfGuestsLabel.text = "Количество гостей: \(value)"
134+ infoLabel.text = getNumberOfCalians(value)
135+
136+ guard let d = data else { return }
137+
138+ data = ReservationData(establishment: d.establishment,
139+ startTime: d.startTime,
140+ endTime: d.endTime,
141+ numberOfGuests: value,
142+ reservedTable: d.reservedTable)
143+ }
144+
145+ @objc func callAlmin() {
146+ guard
147+ let m = model?.establishment,
148+ let phone = TotalStorage.standard.getEstablishment(m)?.admin,
149+ let urlPhone = URL(string: "tel://79\(phone)") else { return }
150+
151+ UIApplication.shared.open(urlPhone)
152+ }
153+
154+ func getNumberOfCalians(_ sliderValue: Int) -> String {
155+ return "Минимальное количество кальянов: \(sliderValue > 6 ? 2 : 1)"
156+ }
157+
158+ // MARK: - Setup
159+
160+ /// Тут происходит установка интервалов. Разное для клиента и админа
161+ func setUpIntervals(_ isAdmin: Bool) {
162+ guard let startPoint = startDate else { return }
163+
164+ let startingPoint = isAdmin ? startPoint.getAdminsStartingPoint() : Constants.clientStartingPoint
165+ let endingPoint = startingPoint + (isAdmin ? Constants.adminDuration : Constants.clientDuration)
166+
167+ for period in startingPoint...endingPoint {
168+ let timePointView = TimePointView.loadFromNib()
169+ timePointView?.setUp(withTimePoint: period)
170+ let view = UIView(frame: CGRect(x: 0, y: 0, width: 35, height: 106))
171+ view.addSubviewThatFills(timePointView)
172+ intervalsStackView.addArrangedSubview(view)
173+ }
174+ }
175+
176+
177+ private func setUpBookingPeriod(_ startTime: Date, _ endTime: Date? = nil) {
178+ self.scrollView.addSubview(startPoint)
179+ self.scrollView.addSubview(endPoint)
180+ self.scrollView.addSubview(fillInterval)
181+
182+ guard let startDate = startDate else { return }
183+
184+ let startConstr = CGFloat(startTime.getMinutesPeriods(fromStart: startDate) * Constants.widthTimePoint)
185+
186+ scrollView.setContentOffset(CGPoint(x: startConstr - 50, y: 0), animated: true)
187+
188+ startLeadingConstraint = startPoint.leftAnchor.constraint(equalTo: scrollView.leftAnchor,
189+ constant: startConstr)
190+
191+ if let end = endTime {
192+ let endConstr = CGFloat(end.getMinutesPeriods(fromStart: startDate) * Constants.widthTimePoint)
193+ endLeadingConstraint = endPoint.leftAnchor.constraint(equalTo: scrollView.leftAnchor,
194+ constant: endConstr)
195+ } else {
196+ endLeadingConstraint = endPoint.leftAnchor.constraint(equalTo: scrollView.leftAnchor,
197+ constant:startConstr + Constants.minBookingLength)
198+ }
199+
200+ NSLayoutConstraint.activate([
201+
202+ startPoint.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0),
203+ endPoint.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0),
204+
205+ startPoint.widthAnchor.constraint(equalToConstant: Constants.pointWidth),
206+ endPoint.widthAnchor.constraint(equalToConstant: Constants.pointWidth),
207+
208+ startPoint.heightAnchor.constraint(equalToConstant: Constants.pointHeight),
209+ endPoint.heightAnchor.constraint(equalToConstant: Constants.pointHeight),
210+
211+ startLeadingConstraint,
212+ endLeadingConstraint,
213+
214+ fillInterval.leftAnchor.constraint(equalTo: startPoint.rightAnchor, constant: 0),
215+ fillInterval.rightAnchor.constraint(equalTo: endPoint.leftAnchor, constant: 0),
216+
217+ fillInterval.heightAnchor.constraint(equalToConstant: Constants.pointHeight),
218+ fillInterval.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0)
219+ ])
220+
221+ let scrollViewPanStartGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanStart(recognizer:)))
222+ startPoint.addGestureRecognizer(scrollViewPanStartGesture)
223+
224+ let scrollViewPanEndGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanEnd(recognizer:)))
225+ endPoint.addGestureRecognizer(scrollViewPanEndGesture)
226+ }
227+
228+ func setUpReservedIntervals(_ reservations: [ReservationPeriod], _ isAdmin: Bool) {
229+
230+ for reservation in reservations {
231+ let uiview = UIView(frame: CGRect(x: 0, y: 0, width: Constants.widthTimePoint * reservation.duration, height: Constants.heightIntervals))
232+ uiview.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.5)
233+
234+
235+ uiview.translatesAutoresizingMaskIntoConstraints = false
236+ scrollView.addSubview(uiview)
237+
238+ guard let startDate = startDate else { return }
239+
240+ let s = reservation.startTime.getMinutesPeriods(fromStart: startDate) * Constants.widthTimePoint
241+ let d = reservation.duration * Constants.widthTimePoint
242+
243+ let startTime = s < 0 ? 0 : s
244+
245+ let total = (isAdmin ? Constants.adminDuration : Constants.clientDuration) * Constants.widthTimePoint
246+ var duration = 0
247+ if s < 0 {
248+ duration = reservation.endTime.getMinutesPeriods(fromStart: startDate) * Constants.widthTimePoint
249+ } else {
250+ duration = (s + d) > total ? total - s : d
251+ }
252+
253+ NSLayoutConstraint.activate([
254+ uiview.bottomAnchor.constraint(equalToSystemSpacingBelow: scrollView.bottomAnchor, multiplier: 0),
255+ uiview.leftAnchor.constraint(equalTo: scrollView.leftAnchor,
256+ constant: CGFloat(Constants.widthTimePoint / 2 + startTime)),
257+ uiview.widthAnchor.constraint(equalToConstant: CGFloat(duration)),
258+ uiview.heightAnchor.constraint(equalToConstant: CGFloat(Constants.heightIntervals))
259+ ])
260+ }
261+ }
262+
263+ func bind(model: SecondStepModel) {
264+ self.model = model
265+
266+ guard let table = TotalStorage.standard.getTable(establishment: model.establishment,
267+ table: model.table) else { return }
268+ self.guestSlider.maximumValue = Float(table.maxGuestNumber)
269+ }
270+
271+ // MARK: - Pan
272+
273+ @objc func handlePanStart(recognizer:UIPanGestureRecognizer) {
274+
275+ let translation = recognizer.translation(in: self.intervalsStackView)
276+ let duration = abs(startLeadingConstraint.constant + translation.x - endLeadingConstraint.constant)
277+
278+ if let view = recognizer.view, duration >= Constants.minBookingLength {
279+ startLeadingConstraint.constant += translation.x
280+
281+ changeTime(startLeadingConstraint, .start)
282+
283+ view.setNeedsUpdateConstraints()
284+ }
285+
286+ recognizer.setTranslation(CGPoint.zero, in: self.intervalsStackView)
287+ }
288+
289+ @objc func handlePanEnd(recognizer:UIPanGestureRecognizer) {
290+
291+ let translation = recognizer.translation(in: self.intervalsStackView)
292+ let duration = abs(startLeadingConstraint.constant - (endLeadingConstraint.constant + translation.x))
293+
294+ if let view = recognizer.view, duration >= Constants.minBookingLength {
295+ endLeadingConstraint.constant += translation.x
296+
297+ changeTime(endLeadingConstraint, .end)
298+ view.setNeedsUpdateConstraints()
299+ }
300+
301+ recognizer.setTranslation(CGPoint.zero, in: self.intervalsStackView)
302+ }
303+
304+ func changeTime(_ constraint: NSLayoutConstraint, _ period: Period) {
305+ guard let startDate = startDate, let d = data else { return }
306+
307+ let offset = Int(constraint.constant) % Constants.widthTimePoint
308+
309+ if offset == 0 {
310+ let p = Int(constraint.constant) / Constants.widthTimePoint
311+ let time = startDate.addPeriods(p)
312+
313+ switch period {
314+ case .start:
315+ data = ReservationData(establishment: d.establishment,
316+ startTime: time,
317+ endTime: d.endTime,
318+ numberOfGuests: d.numberOfGuests,
319+ reservedTable: d.reservedTable)
320+ case .end:
321+ data = ReservationData(establishment: d.establishment,
322+ startTime: d.startTime,
323+ endTime: time,
324+ numberOfGuests: d.numberOfGuests,
325+ reservedTable: d.reservedTable)
326+ }
327+ }
328+ }
329+}
330+
331+extension SecondStepView: UIScrollViewDelegate {
332+
333+}
334+
335+// MARK: - Nested types
336+
337+extension SecondStepView {
338+ enum Constants {
339+ static let widthTimePoint = 11
340+
341+ static let adminDuration = 288
342+ static let clientDuration = 90
343+ // 12:00 = 12 * 6
344+ static let clientStartingPoint = 72
345+
346+ static let pointWidth: CGFloat = 19
347+ static let pointHeight: CGFloat = 85
348+
349+ static let minBookingLength: CGFloat = 132
350+
351+ static let heightIntervals = 85
352+ }
353+
354+ enum Period {
355+ case start
356+ case end
357+ }
358+}
Hookah Tau/Controllers/Client/Reservations/Steps/2/SecondStepView.xibnew file+157
@@ -0,0 +1,157 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina4_7" orientation="portrait" appearance="light"/>
4+ <dependencies>
5+ <deployment identifier="iOS"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8+ <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
9+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10+ </dependencies>
11+ <objects>
12+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
13+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
14+ <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="SecondStepView" customModule="Hookah_Tau" customModuleProvider="target">
15+ <rect key="frame" x="0.0" y="0.0" width="414" height="394"/>
16+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
17+ <subviews>
18+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="bJ1-1q-VXq">
19+ <rect key="frame" x="20" y="20" width="374" height="131.5"/>
20+ <subviews>
21+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="Dkh-B7-3Dl">
22+ <rect key="frame" x="16.5" y="0.0" width="341.5" height="92.5"/>
23+ <subviews>
24+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Забронировать 7 столик на 3 человека 29 марта с 3:00 до 5:30?" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7M9-lI-egu">
25+ <rect key="frame" x="0.0" y="0.0" width="341.5" height="41"/>
26+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
27+ <nil key="textColor"/>
28+ <nil key="highlightedColor"/>
29+ </label>
30+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Минимальное количество кальянов: 2" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zMP-Wa-N6b">
31+ <rect key="frame" x="11" y="72" width="319" height="20.5"/>
32+ <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
33+ <nil key="textColor"/>
34+ <nil key="highlightedColor"/>
35+ </label>
36+ </subviews>
37+ </stackView>
38+ <label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PHb-Nt-9I2">
39+ <rect key="frame" x="47" y="102.5" width="280.5" height="29"/>
40+ <string key="text">Если Вам нужно что-то особенное, Вы можете
41+связаться с администратором. </string>
42+ <fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="12"/>
43+ <color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
44+ <nil key="highlightedColor"/>
45+ </label>
46+ </subviews>
47+ </stackView>
48+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="9c7-IZ-n2p">
49+ <rect key="frame" x="20" y="171.5" width="373.5" height="60.5"/>
50+ <subviews>
51+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Количество гостей: 3" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QuY-68-2ax">
52+ <rect key="frame" x="0.0" y="0.0" width="373.5" height="20.5"/>
53+ <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
54+ <nil key="textColor"/>
55+ <nil key="highlightedColor"/>
56+ </label>
57+ <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="3" minValue="1" maxValue="10" translatesAutoresizingMaskIntoConstraints="NO" id="TrY-MC-Ty0">
58+ <rect key="frame" x="-2" y="30.5" width="377.5" height="31"/>
59+ <connections>
60+ <action selector="sliderValueChanged:" destination="iN0-l3-epB" eventType="valueChanged" id="ekZ-3h-EeB"/>
61+ </connections>
62+ </slider>
63+ </subviews>
64+ </stackView>
65+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RJE-Hk-KNh">
66+ <rect key="frame" x="0.0" y="252" width="414" height="106"/>
67+ <subviews>
68+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dmc-2e-y3T">
69+ <rect key="frame" x="0.0" y="21" width="414" height="85"/>
70+ <subviews>
71+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lBc-2o-oni">
72+ <rect key="frame" x="0.0" y="0.0" width="414" height="1"/>
73+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
74+ <constraints>
75+ <constraint firstAttribute="height" constant="1" id="dFH-fE-V61"/>
76+ </constraints>
77+ </view>
78+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7Du-Fg-z1t">
79+ <rect key="frame" x="0.0" y="84" width="414" height="1"/>
80+ <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
81+ <constraints>
82+ <constraint firstAttribute="height" constant="1" id="hal-Zc-mvq"/>
83+ <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="1" id="mCA-jf-NGh"/>
84+ </constraints>
85+ </view>
86+ </subviews>
87+ <color key="backgroundColor" red="0.89019607840000003" green="0.89019607840000003" blue="0.89019607840000003" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
88+ <constraints>
89+ <constraint firstAttribute="trailing" secondItem="7Du-Fg-z1t" secondAttribute="trailing" id="5fu-5i-psO"/>
90+ <constraint firstAttribute="trailing" secondItem="lBc-2o-oni" secondAttribute="trailing" id="7eP-jA-V9V"/>
91+ <constraint firstItem="lBc-2o-oni" firstAttribute="leading" secondItem="dmc-2e-y3T" secondAttribute="leading" id="CA6-4b-6ZK"/>
92+ <constraint firstItem="7Du-Fg-z1t" firstAttribute="leading" secondItem="dmc-2e-y3T" secondAttribute="leading" id="YwH-ns-ecE"/>
93+ <constraint firstItem="lBc-2o-oni" firstAttribute="top" secondItem="dmc-2e-y3T" secondAttribute="top" id="ja1-YQ-A2D"/>
94+ <constraint firstAttribute="height" constant="85" id="rbN-al-oWi"/>
95+ <constraint firstAttribute="bottom" secondItem="7Du-Fg-z1t" secondAttribute="bottom" id="wa8-GY-qKm"/>
96+ </constraints>
97+ </view>
98+ <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zk1-3E-2kS">
99+ <rect key="frame" x="0.0" y="0.0" width="414" height="106"/>
100+ <subviews>
101+ <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IIO-je-eBt">
102+ <rect key="frame" x="10" y="0.0" width="414" height="106"/>
103+ </stackView>
104+ </subviews>
105+ <constraints>
106+ <constraint firstAttribute="bottom" secondItem="IIO-je-eBt" secondAttribute="bottom" id="FFo-Gu-FQi"/>
107+ <constraint firstItem="IIO-je-eBt" firstAttribute="top" secondItem="zk1-3E-2kS" secondAttribute="top" id="GCb-A1-Nm9"/>
108+ <constraint firstItem="IIO-je-eBt" firstAttribute="width" secondItem="zk1-3E-2kS" secondAttribute="width" priority="250" id="NNQ-JX-gov"/>
109+ <constraint firstItem="IIO-je-eBt" firstAttribute="leading" secondItem="zk1-3E-2kS" secondAttribute="leading" constant="10" id="SFN-at-Ckn"/>
110+ <constraint firstItem="IIO-je-eBt" firstAttribute="height" secondItem="zk1-3E-2kS" secondAttribute="height" id="rPM-R0-lcb"/>
111+ <constraint firstAttribute="trailing" secondItem="IIO-je-eBt" secondAttribute="trailing" constant="10" id="xBZ-av-Hao"/>
112+ </constraints>
113+ <viewLayoutGuide key="contentLayoutGuide" id="AEC-Ih-oKP"/>
114+ <viewLayoutGuide key="frameLayoutGuide" id="ciz-kC-nwk"/>
115+ </scrollView>
116+ </subviews>
117+ <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
118+ <constraints>
119+ <constraint firstAttribute="height" constant="106" id="DIa-m5-0fc"/>
120+ <constraint firstItem="zk1-3E-2kS" firstAttribute="top" secondItem="RJE-Hk-KNh" secondAttribute="top" id="gWD-k8-Ycq"/>
121+ <constraint firstAttribute="trailing" secondItem="zk1-3E-2kS" secondAttribute="trailing" id="iuc-Gd-ZUo"/>
122+ <constraint firstAttribute="bottom" secondItem="dmc-2e-y3T" secondAttribute="bottom" id="k3O-Eo-mm5"/>
123+ <constraint firstItem="zk1-3E-2kS" firstAttribute="leading" secondItem="RJE-Hk-KNh" secondAttribute="leading" id="qT5-vh-S0P"/>
124+ <constraint firstAttribute="trailing" secondItem="dmc-2e-y3T" secondAttribute="trailing" id="tTC-4l-vfe"/>
125+ <constraint firstAttribute="bottom" secondItem="zk1-3E-2kS" secondAttribute="bottom" id="whX-aj-8o9"/>
126+ <constraint firstItem="dmc-2e-y3T" firstAttribute="leading" secondItem="RJE-Hk-KNh" secondAttribute="leading" id="ymc-Tp-Lqg"/>
127+ </constraints>
128+ </view>
129+ </subviews>
130+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
131+ <constraints>
132+ <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="RJE-Hk-KNh" secondAttribute="bottom" constant="36" id="0W3-e2-hCU"/>
133+ <constraint firstItem="9c7-IZ-n2p" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="94y-7J-ksb"/>
134+ <constraint firstItem="9c7-IZ-n2p" firstAttribute="top" secondItem="bJ1-1q-VXq" secondAttribute="bottom" constant="20" id="9TT-vO-7PZ"/>
135+ <constraint firstItem="RJE-Hk-KNh" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="AgS-kP-UNE"/>
136+ <constraint firstItem="RJE-Hk-KNh" firstAttribute="top" secondItem="9c7-IZ-n2p" secondAttribute="bottom" constant="20" id="FAI-xj-uWk"/>
137+ <constraint firstAttribute="trailing" secondItem="bJ1-1q-VXq" secondAttribute="trailing" constant="20" id="OCH-eC-kP5"/>
138+ <constraint firstItem="bJ1-1q-VXq" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="PCm-nY-M6p"/>
139+ <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="9c7-IZ-n2p" secondAttribute="trailing" constant="20.5" id="Rh7-V2-v2u"/>
140+ <constraint firstItem="bJ1-1q-VXq" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="20" id="SnG-Cy-hHq"/>
141+ <constraint firstItem="RJE-Hk-KNh" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="fW0-Tt-MpN"/>
142+ </constraints>
143+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
144+ <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
145+ <connections>
146+ <outlet property="guestSlider" destination="TrY-MC-Ty0" id="mR0-wv-AM7"/>
147+ <outlet property="infoLabel" destination="zMP-Wa-N6b" id="htu-ql-T0O"/>
148+ <outlet property="intervalsStackView" destination="IIO-je-eBt" id="gaP-LX-Xed"/>
149+ <outlet property="numberOfGuestsLabel" destination="QuY-68-2ax" id="DvK-dr-c3J"/>
150+ <outlet property="scrollView" destination="zk1-3E-2kS" id="b8R-jY-2Q3"/>
151+ <outlet property="specialLabel" destination="PHb-Nt-9I2" id="hXL-Je-dax"/>
152+ <outlet property="totalBookingLabel" destination="7M9-lI-egu" id="7YU-yI-Gm4"/>
153+ </connections>
154+ <point key="canvasLocation" x="-8" y="70"/>
155+ </view>
156+ </objects>
157+</document>
Hookah Tau/Controllers/Client/Reservations/Steps/3/ThirdStepReservationCoordinator.swiftnew file+57
@@ -0,0 +1,57 @@
1+//
2+// ThirdStepReservationCoordinator.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 23/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class ThirdStepReservationCoordinator: BaseCoordinator {
12+
13+ // MARK: - Properties
14+
15+ var didFinish: (() -> Void)?
16+
17+ var mapView: MapImageScroll?
18+
19+ /// Объект регистрации, созданной или существующей
20+ var resrvation: Reservation?
21+
22+ var reservationVC: ThirdStepReservationViewController?
23+
24+ // MARK: - Lifecycle
25+
26+ override func start() {
27+ let storyboard = UIStoryboard(name: "Reservation", bundle: nil)
28+ reservationVC = storyboard.instantiateViewController(withIdentifier: "ThirdStepReservationViewController") as? ThirdStepReservationViewController
29+
30+ reservationVC?.coordinator = self
31+ reservationVC?.mapView = mapView
32+ reservationVC?.reservation = resrvation
33+
34+ guard let r = reservationVC else { return }
35+ navigationController?.pushViewController(r, animated: false)
36+ }
37+
38+ /// You need to pass reservation object and map describing booked table
39+ func change(_ reservation: Reservation) {
40+ let changeCoordinator = ChangeReservationCoordinator(navigationController: navigationController)
41+
42+ changeCoordinator.reservation = reservation
43+
44+ changeCoordinator.didFinish = { [weak self] res in
45+ self?.removeDependency(changeCoordinator)
46+ self?.navigationController?.popViewController(animated: false)
47+ self?.reservationVC?.reservation = res
48+ }
49+
50+ changeCoordinator.start()
51+ }
52+
53+ /// Goes back to `allReservations` screen
54+ func close() {
55+ didFinish?()
56+ }
57+}
Hookah Tau/Controllers/Client/Reservations/Steps/3/ThirdStepReservationViewController.swiftnew file+156
@@ -0,0 +1,156 @@
1+//
2+// ThirdStepReservationViewController.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 23/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class ThirdStepReservationViewController: BaseViewController {
12+
13+ // MARK: - IBAOutlets
14+
15+ @IBOutlet weak var containerView: UIView!
16+
17+ @IBOutlet weak var contentForMap: UIView!
18+
19+ // MARK: - Properties
20+
21+ var mapView: MapImageScroll?
22+
23+ weak var coordinator: ThirdStepReservationCoordinator?
24+
25+ var thirdStepView: ThirdStepView?
26+
27+ var reservation: Reservation? {
28+ didSet {
29+ guard let r = reservation,
30+ let data = TotalStorage.standard.getEstablishment(r.establishment)
31+ else { return }
32+
33+ navigationItem.title = data.address
34+
35+ guard let res = reservation else { return }
36+ thirdStepView?.bind(withModel: res)
37+ }
38+ }
39+
40+ var reservationService: ReservationsService?
41+
42+ /// "Отменить бронь"
43+ let cancelButton: Button = {
44+ let button = Button()
45+ let style = BlackButtonStyle()
46+ style.apply(to: button, withTitle: "ОТМЕНИТЬ БРОНЬ")
47+ return button
48+ }()
49+
50+ /// "Изменить бронь"
51+ let changeButton: Button = {
52+ let button = Button()
53+ let style = BlackButtonStyle()
54+ style.apply(to: button, withTitle: "ИЗМЕНИТЬ")
55+ return button
56+ }()
57+
58+ // MARK: - Lifecycle
59+
60+ override func viewDidLoad() {
61+ super.viewDidLoad()
62+
63+ navigationItem.hidesBackButton = true
64+ setupContainer()
65+ setupButtons()
66+ setupMap()
67+
68+ reservationService = ReservationsService(apiClient: APIClient.shared)
69+ navigationController?.navigationBar.prefersLargeTitles = false
70+ }
71+
72+ override func viewWillAppear(_ animated: Bool) {
73+ super.viewWillAppear(animated)
74+
75+ tabBarController?.tabBar.isHidden = true
76+ }
77+
78+ // MARK: - Setup
79+
80+ func setupMap() {
81+ guard let reservation = reservation else {
82+ return
83+ }
84+
85+ let width = view.frame.width
86+ if reservation.establishment == 1 {
87+ mapView = MapView1.loadFromNib()
88+ mapView?.scrollViewParent.contentInset = UIEdgeInsets(top: 0,
89+ left: width / 2,
90+ bottom: 200,
91+ right: width / 2)
92+
93+ mapView?.scrollViewParent.setContentOffset(CGPoint(x: 0, y: 50), animated: false)
94+ } else {
95+ mapView = MapView2.loadFromNib()
96+ mapView?.scrollViewParent.setContentOffset(CGPoint(x: 0, y: -100), animated: false)
97+ mapView?.scrollViewParent.contentInset = UIEdgeInsets(top: 100,
98+ left: width / 2,
99+ bottom: 100,
100+ right: width / 2)
101+ }
102+
103+ contentForMap.addSubviewThatFills(mapView)
104+
105+ mapView?.isUserInteractionEnabled = false
106+ mapView?.scrollToTable(table: reservation.reservedTable)
107+ }
108+
109+ func setupContainer() {
110+ thirdStepView = ThirdStepView.loadFromNib()
111+ containerView.addSubviewThatFills(thirdStepView)
112+
113+ guard let res = reservation else { return }
114+ thirdStepView?.bind(withModel: res)
115+ }
116+
117+ func setupButtons() {
118+ addStackViewWithButtons(leftBtn: cancelButton,
119+ rightBtn: changeButton,
120+ constant: -containerView.frame.height - 20)
121+
122+ changeButton.addTarget(self, action: #selector(change), for: .touchUpInside)
123+ cancelButton.addTarget(self, action: #selector(cancelBooking), for: .touchUpInside)
124+ thirdStepView?.closeButton.addTarget(self, action: #selector(close), for: .touchUpInside)
125+ }
126+
127+
128+ // MARK: - handlers for buttons
129+
130+ @objc func change() {
131+ guard
132+ let res = reservation
133+ else { return }
134+
135+ coordinator?.change(res)
136+ }
137+
138+ @objc func cancelBooking() {
139+ guard let res = reservation else { return }
140+
141+ cancelButton.loading = true
142+ reservationService?.deleteReservation(uuid: res.uuid, completion: { [weak self] (result) in
143+ self?.cancelButton.loading = false
144+
145+ if result {
146+ self?.close()
147+ } else {
148+ self?.displayAlert(with: "Не удалось отменить бронь, попробуйте еще раз!")
149+ }
150+ })
151+ }
152+
153+ @objc func close() {
154+ coordinator?.close()
155+ }
156+}
Hookah Tau/Controllers/Client/Reservations/Steps/3/ThirdStepView.swiftnew file+177
@@ -0,0 +1,177 @@
1+//
2+// ThirdStepView.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 23/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+struct ThirdStepViewModel {
12+ var timeIntervalView: UIView
13+}
14+
15+class ThirdStepView: UIView {
16+
17+ // MARK: - IBAOutlets
18+
19+ @IBOutlet weak var totalLabel: UILabel!
20+
21+ @IBOutlet weak var infoLabel: UILabel!
22+
23+ @IBOutlet weak var closeButton: Button! {
24+ didSet {
25+ let style = BlackButtonStyle()
26+ style.apply(to: closeButton, withTitle: "ЗАКРЫТЬ")
27+ }
28+ }
29+
30+ @IBOutlet weak var timeInterval: UIView!
31+
32+ @IBOutlet weak var stackView: UIStackView!
33+
34+ @IBOutlet weak var scrollView: UIScrollView!
35+
36+ // MARK: - Properties
37+
38+ /// Время начала вертелки.
39+ var startDate: Date?
40+
41+ // констрейнты начала и конца интервала
42+ var startLeadingConstraint: NSLayoutConstraint!
43+ var endLeadingConstraint: NSLayoutConstraint!
44+
45+ var reservation: Reservation? {
46+ didSet {
47+ // isAdmin
48+ let isAdmin = DataStorage.standard.getUserModel()?.isAdmin ?? false
49+ startDate = reservation?.startTime.addHours(-1)
50+
51+ setupStackView(isAdmin)
52+ setUpBookingPeriod()
53+ }
54+ }
55+
56+ // MARK: - bind
57+
58+ func bind(withModel model: Reservation) {
59+ reservation = model
60+ let date = format(model.startTime, model.endTime)
61+
62+ totalLabel.text = "Забронирован \(model.reservedTable) столик на \(model.numberOfGuests)-х\n \(date)"
63+
64+ infoLabel.text = "Минимальное количество кальянов: \(countTotalNumber(model.numberOfGuests))"
65+ }
66+
67+ private func format(_ startDate: Date, _ endDate: Date) -> String {
68+ let dateFormatter = DateFormatter()
69+ dateFormatter.calendar = Calendar.current
70+ dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
71+ dateFormatter.dateFormat = "MM.dd, с HH:mm по"
72+
73+ var newDateString = "\(dateFormatter.string(from: startDate))"
74+
75+ dateFormatter.dateFormat = "HH:mm"
76+ newDateString += " \(dateFormatter.string(from: endDate))"
77+
78+ return newDateString
79+ }
80+
81+ private func countTotalNumber(_ people: Int) -> Int {
82+ let num = people > 6 ? 2 : 1
83+ return num
84+ }
85+
86+ var startPoint: UIView = {
87+ var view = UIView()
88+ view.backgroundColor = #colorLiteral(red: 0.2901960784, green: 0.5647058824, blue: 0.8862745098, alpha: 1)
89+ view.translatesAutoresizingMaskIntoConstraints = false
90+ return view
91+ }()
92+
93+ var endPoint: UIView = {
94+ var view = UIView()
95+ view.backgroundColor = #colorLiteral(red: 0.2901960784, green: 0.5647058824, blue: 0.8862745098, alpha: 1)
96+ view.translatesAutoresizingMaskIntoConstraints = false
97+ return view
98+ }()
99+
100+ /// Интервал
101+ var fillInterval: UIView = {
102+ var view = UIView()
103+ view.backgroundColor = #colorLiteral(red: 0, green: 0.5921568627, blue: 1, alpha: 0.3426262843)
104+ view.translatesAutoresizingMaskIntoConstraints = false
105+ return view
106+ }()
107+
108+ func setupStackView(_ isAdmin: Bool) {
109+ guard let startPoint = startDate else { return }
110+
111+ let startingPoint = startPoint.getAdminsStartingPoint()
112+ let endingPoint = startingPoint + (isAdmin ? Constants.adminDuration : Constants.clientDuration)
113+
114+ for period in startingPoint...endingPoint {
115+ let timePointView = TimePointView.loadFromNib()
116+ timePointView?.setUp(withTimePoint: period)
117+ let view = UIView(frame: CGRect(x: 0, y: 0, width: 35, height: 106))
118+ view.addSubviewThatFills(timePointView)
119+ stackView.addArrangedSubview(view)
120+ }
121+ }
122+
123+ func setUpBookingPeriod() {
124+ self.scrollView.addSubview(startPoint)
125+ self.scrollView.addSubview(endPoint)
126+ self.scrollView.addSubview(fillInterval)
127+
128+ guard
129+ let startDate = startDate,
130+ let startTime = reservation?.startTime,
131+ let endTime = reservation?.endTime else { return }
132+
133+ let startConstr = CGFloat(startTime.getMinutesPeriods(fromStart: startDate) * Constants.widthTimePoint) + 3
134+ startLeadingConstraint = startPoint.leftAnchor.constraint(equalTo: scrollView.leftAnchor,
135+ constant: startConstr)
136+
137+ let endConstr = CGFloat(endTime.getMinutesPeriods(fromStart: startDate) * Constants.widthTimePoint) + 3
138+ endLeadingConstraint = endPoint.leftAnchor.constraint(equalTo: scrollView.leftAnchor,
139+ constant: endConstr)
140+
141+ scrollView.setContentOffset(CGPoint(x: startConstr - 50, y: 0), animated: true)
142+
143+ NSLayoutConstraint.activate([
144+
145+ startPoint.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0),
146+ endPoint.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0),
147+
148+ startPoint.widthAnchor.constraint(equalToConstant: Constants.pointWidth),
149+ endPoint.widthAnchor.constraint(equalToConstant: Constants.pointWidth),
150+
151+ startPoint.heightAnchor.constraint(equalToConstant: Constants.pointHeight),
152+ endPoint.heightAnchor.constraint(equalToConstant: Constants.pointHeight),
153+
154+ startLeadingConstraint,
155+ endLeadingConstraint,
156+
157+ fillInterval.leftAnchor.constraint(equalTo: startPoint.rightAnchor, constant: 0),
158+ fillInterval.rightAnchor.constraint(equalTo: endPoint.leftAnchor, constant: 0),
159+
160+ fillInterval.heightAnchor.constraint(equalToConstant: Constants.pointHeight),
161+ fillInterval.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0)
162+ ])
163+ }
164+}
165+
166+extension ThirdStepView {
167+ enum Constants {
168+ static let widthTimePoint = 11
169+ static let pointWidth: CGFloat = 5
170+ static let pointHeight: CGFloat = 85
171+
172+ static let adminDuration = 288
173+ static let clientDuration = 90
174+ // 12:00 = 12 * 6
175+ static let clientStartingPoint = 72
176+ }
177+}
Hookah Tau/Controllers/Client/Reservations/Steps/3/ThirdStepView.xibnew file+144
@@ -0,0 +1,144 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina4_7" orientation="portrait" appearance="light"/>
4+ <dependencies>
5+ <deployment identifier="iOS"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8+ <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
9+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10+ </dependencies>
11+ <objects>
12+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
13+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
14+ <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="ThirdStepView" customModule="Hookah_Tau" customModuleProvider="target">
15+ <rect key="frame" x="0.0" y="0.0" width="414" height="340"/>
16+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
17+ <subviews>
18+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="21" translatesAutoresizingMaskIntoConstraints="NO" id="DL4-0a-WxC">
19+ <rect key="frame" x="20" y="20" width="374" height="82.5"/>
20+ <subviews>
21+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Забронирован 7 столик на 3 человека 29 марта с 3:00 до 5:30!" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xHF-9h-q9F">
22+ <rect key="frame" x="19.5" y="0.0" width="335" height="41"/>
23+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
24+ <nil key="textColor"/>
25+ <nil key="highlightedColor"/>
26+ </label>
27+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Минимальное количество кальянов: 2" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7xJ-nJ-IFN">
28+ <rect key="frame" x="27.5" y="62" width="319" height="20.5"/>
29+ <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
30+ <nil key="textColor"/>
31+ <nil key="highlightedColor"/>
32+ </label>
33+ </subviews>
34+ </stackView>
35+ <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacingType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="0H2-jJ-gOj">
36+ <rect key="frame" x="20" y="132.5" width="374" height="45"/>
37+ <subviews>
38+ <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Tick" translatesAutoresizingMaskIntoConstraints="NO" id="lcW-xm-Gb7">
39+ <rect key="frame" x="0.0" y="0.0" width="230" height="45"/>
40+ </imageView>
41+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QjM-My-aZ0" customClass="Button" customModule="Hookah_Tau" customModuleProvider="target">
42+ <rect key="frame" x="238" y="4" width="136" height="37"/>
43+ <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
44+ <constraints>
45+ <constraint firstAttribute="width" constant="136" id="No6-wb-pIe"/>
46+ <constraint firstAttribute="height" constant="37" id="SOm-Gm-2i0"/>
47+ </constraints>
48+ <state key="normal" title="Button"/>
49+ </button>
50+ </subviews>
51+ </stackView>
52+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ByV-f1-mVO">
53+ <rect key="frame" x="0.0" y="207.5" width="414" height="106"/>
54+ <subviews>
55+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JpA-EH-PLI">
56+ <rect key="frame" x="0.0" y="21" width="414" height="85"/>
57+ <subviews>
58+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TgV-cB-bMd">
59+ <rect key="frame" x="0.0" y="0.0" width="414" height="1"/>
60+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
61+ <constraints>
62+ <constraint firstAttribute="height" constant="1" id="kOS-eB-bWd"/>
63+ </constraints>
64+ </view>
65+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nzW-L7-eY8">
66+ <rect key="frame" x="0.0" y="84" width="414" height="1"/>
67+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
68+ <constraints>
69+ <constraint firstAttribute="height" constant="1" id="BNR-Cz-HJe"/>
70+ </constraints>
71+ </view>
72+ </subviews>
73+ <color key="backgroundColor" red="0.8901960784313725" green="0.8901960784313725" blue="0.8901960784313725" alpha="1" colorSpace="calibratedRGB"/>
74+ <constraints>
75+ <constraint firstItem="TgV-cB-bMd" firstAttribute="leading" secondItem="JpA-EH-PLI" secondAttribute="leading" id="3ZT-oY-Rzz"/>
76+ <constraint firstAttribute="height" constant="85" id="7jH-zS-CoD"/>
77+ <constraint firstAttribute="trailing" secondItem="nzW-L7-eY8" secondAttribute="trailing" id="HSn-Vn-8Kb"/>
78+ <constraint firstItem="TgV-cB-bMd" firstAttribute="top" secondItem="JpA-EH-PLI" secondAttribute="top" id="K34-18-ZM8"/>
79+ <constraint firstAttribute="bottom" secondItem="nzW-L7-eY8" secondAttribute="bottom" id="hKT-AB-KQS"/>
80+ <constraint firstItem="nzW-L7-eY8" firstAttribute="leading" secondItem="JpA-EH-PLI" secondAttribute="leading" id="lqp-3j-OoO"/>
81+ <constraint firstAttribute="trailing" secondItem="TgV-cB-bMd" secondAttribute="trailing" id="r1u-XE-GXS"/>
82+ </constraints>
83+ </view>
84+ <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gQW-4g-8T5">
85+ <rect key="frame" x="0.0" y="0.0" width="414" height="106"/>
86+ <subviews>
87+ <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gfj-mL-wQq">
88+ <rect key="frame" x="0.0" y="0.0" width="414" height="106"/>
89+ </stackView>
90+ </subviews>
91+ <constraints>
92+ <constraint firstItem="Gfj-mL-wQq" firstAttribute="width" secondItem="gQW-4g-8T5" secondAttribute="width" priority="250" id="DhE-CT-MGo"/>
93+ <constraint firstItem="Gfj-mL-wQq" firstAttribute="height" secondItem="gQW-4g-8T5" secondAttribute="height" id="JdJ-xb-2kM"/>
94+ <constraint firstAttribute="bottom" secondItem="Gfj-mL-wQq" secondAttribute="bottom" id="Pji-4z-R86"/>
95+ <constraint firstItem="Gfj-mL-wQq" firstAttribute="top" secondItem="gQW-4g-8T5" secondAttribute="top" id="UBW-vr-VEu"/>
96+ <constraint firstAttribute="trailing" secondItem="Gfj-mL-wQq" secondAttribute="trailing" id="gkv-lF-jaW"/>
97+ <constraint firstItem="Gfj-mL-wQq" firstAttribute="leading" secondItem="gQW-4g-8T5" secondAttribute="leading" id="yZy-o3-tDY"/>
98+ </constraints>
99+ <viewLayoutGuide key="contentLayoutGuide" id="jEg-I8-hwu"/>
100+ <viewLayoutGuide key="frameLayoutGuide" id="EFO-bp-t4s"/>
101+ </scrollView>
102+ </subviews>
103+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
104+ <constraints>
105+ <constraint firstItem="JpA-EH-PLI" firstAttribute="leading" secondItem="ByV-f1-mVO" secondAttribute="leading" id="0Yf-vL-RSK"/>
106+ <constraint firstAttribute="trailing" secondItem="JpA-EH-PLI" secondAttribute="trailing" id="N9T-dc-Auk"/>
107+ <constraint firstAttribute="bottom" secondItem="JpA-EH-PLI" secondAttribute="bottom" id="QPT-JY-erJ"/>
108+ <constraint firstItem="gQW-4g-8T5" firstAttribute="top" secondItem="ByV-f1-mVO" secondAttribute="top" id="Qz6-Bm-fcB"/>
109+ <constraint firstAttribute="height" constant="106" id="UWZ-LN-h4r"/>
110+ <constraint firstItem="gQW-4g-8T5" firstAttribute="leading" secondItem="ByV-f1-mVO" secondAttribute="leading" id="gZ2-dm-HGX"/>
111+ <constraint firstAttribute="bottom" secondItem="gQW-4g-8T5" secondAttribute="bottom" id="idD-XC-tGe"/>
112+ <constraint firstAttribute="trailing" secondItem="gQW-4g-8T5" secondAttribute="trailing" id="mWv-Uy-FiK"/>
113+ </constraints>
114+ </view>
115+ </subviews>
116+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
117+ <constraints>
118+ <constraint firstItem="ByV-f1-mVO" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="1g0-ab-erl"/>
119+ <constraint firstItem="ByV-f1-mVO" firstAttribute="top" secondItem="0H2-jJ-gOj" secondAttribute="bottom" constant="30" id="F84-ZL-MWp"/>
120+ <constraint firstItem="0H2-jJ-gOj" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="GR6-gI-ecm"/>
121+ <constraint firstItem="ByV-f1-mVO" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="KKj-7n-eQf"/>
122+ <constraint firstItem="0H2-jJ-gOj" firstAttribute="top" secondItem="DL4-0a-WxC" secondAttribute="bottom" constant="30" id="VbN-sb-Pko"/>
123+ <constraint firstItem="DL4-0a-WxC" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="20" id="cm0-tz-ta4"/>
124+ <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="0H2-jJ-gOj" secondAttribute="trailing" constant="20" id="i3D-sP-KlI"/>
125+ <constraint firstAttribute="trailing" secondItem="DL4-0a-WxC" secondAttribute="trailing" constant="20" id="kHp-8n-OTp"/>
126+ <constraint firstItem="DL4-0a-WxC" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="vOg-X1-y93"/>
127+ </constraints>
128+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
129+ <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
130+ <connections>
131+ <outlet property="closeButton" destination="QjM-My-aZ0" id="Z3P-aG-bf1"/>
132+ <outlet property="infoLabel" destination="7xJ-nJ-IFN" id="jlH-CO-a0K"/>
133+ <outlet property="scrollView" destination="gQW-4g-8T5" id="lLC-JE-ZUm"/>
134+ <outlet property="stackView" destination="Gfj-mL-wQq" id="k5A-hd-BiB"/>
135+ <outlet property="timeInterval" destination="ByV-f1-mVO" id="oB4-jH-8Ot"/>
136+ <outlet property="totalLabel" destination="xHF-9h-q9F" id="W94-2J-w0A"/>
137+ </connections>
138+ <point key="canvasLocation" x="137.59999999999999" y="365.21739130434787"/>
139+ </view>
140+ </objects>
141+ <resources>
142+ <image name="Tick" width="58" height="45"/>
143+ </resources>
144+</document>
Hookah Tau/Controllers/Client/Reservations/Steps/Common/DateView.swiftnew file+18
@@ -0,0 +1,18 @@
1+//
2+// DateView.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 15/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class DateView: UIView {
12+
13+ @IBOutlet weak var dateLabel: UILabel!
14+
15+ func setUp(with date: Date) {
16+ dateLabel.text = "\(date.getDay())"
17+ }
18+}
Hookah Tau/Controllers/Client/Reservations/Steps/Common/DateView.xibnew file+42
@@ -0,0 +1,42 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina4_7" orientation="portrait" appearance="light"/>
4+ <dependencies>
5+ <deployment identifier="iOS"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9+ </dependencies>
10+ <objects>
11+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
12+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
13+ <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="DateView" customModule="Hookah_Tau" customModuleProvider="target">
14+ <rect key="frame" x="0.0" y="0.0" width="31" height="59"/>
15+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
16+ <subviews>
17+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="69" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hzu-lu-5Cc">
18+ <rect key="frame" x="5" y="29" width="21" height="20"/>
19+ <constraints>
20+ <constraint firstAttribute="width" constant="21" id="gdn-d6-auU"/>
21+ </constraints>
22+ <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
23+ <color key="textColor" red="0.60784313725490191" green="0.60784313725490191" blue="0.60784313725490191" alpha="1" colorSpace="calibratedRGB"/>
24+ <nil key="highlightedColor"/>
25+ </label>
26+ </subviews>
27+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
28+ <constraints>
29+ <constraint firstItem="hzu-lu-5Cc" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="fhT-nh-ejJ"/>
30+ <constraint firstItem="hzu-lu-5Cc" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="5" id="mLo-I1-FSM"/>
31+ <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="hzu-lu-5Cc" secondAttribute="trailing" constant="5" id="qSb-Ok-1MH"/>
32+ <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="hzu-lu-5Cc" secondAttribute="bottom" constant="10" id="vtm-8d-jCM"/>
33+ </constraints>
34+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
35+ <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
36+ <connections>
37+ <outlet property="dateLabel" destination="hzu-lu-5Cc" id="n0M-OL-lME"/>
38+ </connections>
39+ <point key="canvasLocation" x="101.59999999999999" y="456.52173913043481"/>
40+ </view>
41+ </objects>
42+</document>
Hookah Tau/Controllers/Client/Reservations/Steps/Common/TimePointView.swiftnew file+52
@@ -0,0 +1,52 @@
1+//
2+// TimePointView.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 15/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class TimePointView: UIView {
12+
13+ // MARK: - Properties
14+
15+ @IBOutlet weak var timePoint: UIView! {
16+ didSet {
17+ timePoint.layer.cornerRadius = 2
18+ }
19+ }
20+
21+ @IBOutlet weak var heightTimePoint: NSLayoutConstraint!
22+
23+
24+
25+ @IBOutlet weak var timePointContainer: UIView! {
26+ didSet {
27+ timePointContainer.layer.masksToBounds = false
28+ timePointContainer.layer.shadowOffset = CGSize(width: 0, height: -3)
29+ timePointContainer.layer.shadowRadius = 1
30+ }
31+ }
32+
33+ @IBOutlet weak var timeLabel: UILabel!
34+
35+ // MARK: - Set up
36+
37+ func setUp(withTimePoint time: Int) {
38+ if time % 6 != 0 {
39+ timeLabel.isHidden = true
40+ heightTimePoint.constant = 24
41+ } else {
42+ timeLabel.isHidden = false
43+ timeLabel.text = TimePointView.getTextTimeFromTimePoint(time)
44+ }
45+ }
46+
47+ // MARK: - Static
48+
49+ static func getTextTimeFromTimePoint(_ time: Int) -> String {
50+ return "\(Int(time / 6) % 24):00"
51+ }
52+}
Hookah Tau/Controllers/Client/Reservations/Steps/Common/TimePointView.xibnew file+83
@@ -0,0 +1,83 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
3+ <device id="retina4_7" orientation="portrait" appearance="light"/>
4+ <dependencies>
5+ <deployment identifier="iOS"/>
6+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
7+ <capability name="Safe area layout guides" minToolsVersion="9.0"/>
8+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9+ </dependencies>
10+ <objects>
11+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
12+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
13+ <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="TimePointView" customModule="Hookah_Tau" customModuleProvider="target">
14+ <rect key="frame" x="0.0" y="0.0" width="11" height="92"/>
15+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
16+ <subviews>
17+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pWD-hx-gp6">
18+ <rect key="frame" x="0.0" y="21" width="11" height="71"/>
19+ <subviews>
20+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yHi-OK-OdD">
21+ <rect key="frame" x="0.0" y="0.0" width="11" height="1"/>
22+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
23+ <constraints>
24+ <constraint firstAttribute="height" constant="1" id="vFV-YQ-dLG"/>
25+ </constraints>
26+ </view>
27+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="D96-RH-9hA">
28+ <rect key="frame" x="4" y="13" width="3" height="45"/>
29+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
30+ <constraints>
31+ <constraint firstAttribute="width" constant="3" id="2jk-1V-VpK"/>
32+ <constraint firstAttribute="height" constant="45" id="TFz-jM-jzh"/>
33+ </constraints>
34+ </view>
35+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xmA-Sn-VW1">
36+ <rect key="frame" x="0.0" y="70" width="11" height="1"/>
37+ <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
38+ <constraints>
39+ <constraint firstAttribute="height" constant="1" id="opb-0M-WVx"/>
40+ </constraints>
41+ </view>
42+ </subviews>
43+ <color key="backgroundColor" red="0.8901960784313725" green="0.8901960784313725" blue="0.8901960784313725" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
44+ <constraints>
45+ <constraint firstItem="yHi-OK-OdD" firstAttribute="leading" secondItem="pWD-hx-gp6" secondAttribute="leading" id="B0T-9H-BtD"/>
46+ <constraint firstItem="yHi-OK-OdD" firstAttribute="top" secondItem="pWD-hx-gp6" secondAttribute="top" id="RNc-ds-Sgr"/>
47+ <constraint firstAttribute="trailing" secondItem="xmA-Sn-VW1" secondAttribute="trailing" id="UwV-GZ-ZJm"/>
48+ <constraint firstAttribute="bottom" secondItem="xmA-Sn-VW1" secondAttribute="bottom" id="jsu-wi-tiv"/>
49+ <constraint firstAttribute="trailing" secondItem="yHi-OK-OdD" secondAttribute="trailing" id="rV7-YM-CIi"/>
50+ <constraint firstItem="xmA-Sn-VW1" firstAttribute="leading" secondItem="pWD-hx-gp6" secondAttribute="leading" id="s0c-se-0fn"/>
51+ <constraint firstItem="D96-RH-9hA" firstAttribute="centerX" secondItem="pWD-hx-gp6" secondAttribute="centerX" id="udJ-PM-6Yh"/>
52+ <constraint firstItem="D96-RH-9hA" firstAttribute="centerY" secondItem="pWD-hx-gp6" secondAttribute="centerY" id="wez-7K-Bt1"/>
53+ <constraint firstAttribute="width" constant="11" id="y4G-wZ-gfe"/>
54+ </constraints>
55+ </view>
56+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="18:00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iIa-WK-OHd">
57+ <rect key="frame" x="-12" y="0.0" width="35" height="16"/>
58+ <fontDescription key="fontDescription" type="system" pointSize="13"/>
59+ <nil key="textColor"/>
60+ <nil key="highlightedColor"/>
61+ </label>
62+ </subviews>
63+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
64+ <constraints>
65+ <constraint firstItem="pWD-hx-gp6" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="A6p-9g-tQu"/>
66+ <constraint firstItem="iIa-WK-OHd" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="Hss-kd-RUN"/>
67+ <constraint firstItem="pWD-hx-gp6" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" id="KBo-cb-dAz"/>
68+ <constraint firstItem="pWD-hx-gp6" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="NHW-lH-rza"/>
69+ <constraint firstItem="iIa-WK-OHd" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="Pfd-58-VXn"/>
70+ <constraint firstItem="pWD-hx-gp6" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="21" id="Wpp-se-wxM"/>
71+ </constraints>
72+ <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
73+ <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
74+ <connections>
75+ <outlet property="heightTimePoint" destination="TFz-jM-jzh" id="INI-mq-Xd4"/>
76+ <outlet property="timeLabel" destination="iIa-WK-OHd" id="jze-go-adl"/>
77+ <outlet property="timePoint" destination="D96-RH-9hA" id="Oby-Tn-zvq"/>
78+ <outlet property="timePointContainer" destination="pWD-hx-gp6" id="ir6-Na-9Ve"/>
79+ </connections>
80+ <point key="canvasLocation" x="130.40000000000001" y="440.7796101949026"/>
81+ </view>
82+ </objects>
83+</document>
Hookah Tau/Controllers/Client/Reservations/Steps/change /ChangeReservationCoordinator.swiftnew file+36
@@ -0,0 +1,36 @@
1+//
2+// ChangeReservationCoordinator.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 02/12/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class ChangeReservationCoordinator: BaseCoordinator {
12+
13+ // MARK: - Peoperties
14+
15+ var reservation: Reservation?
16+
17+ var didFinish: ((Reservation) -> Void)?
18+
19+ // MARK: - Lifecycle
20+
21+ override func start() {
22+ let storyboard = UIStoryboard(name: "Reservation", bundle: nil)
23+ let vc = storyboard.instantiateViewController(withIdentifier: "ChangeReservationViewController") as? ChangeReservationViewController
24+
25+ guard let viewController = vc else { return }
26+
27+ viewController.reservation = reservation
28+ viewController.coordinator = self
29+ navigationController?.pushViewController(viewController, animated: false)
30+ }
31+
32+ /// Закончили редактирование, все хорошо
33+ func finish(_ r: Reservation) {
34+ didFinish?(r)
35+ }
36+}
Hookah Tau/Controllers/Client/Reservations/Steps/change /ChangeReservationViewController.swiftnew file+151
@@ -0,0 +1,151 @@
1+//
2+// ChangeReservationViewController.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 02/12/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class ChangeReservationViewController: BaseViewController {
12+
13+ // MARK: - IBAOutlets
14+
15+ @IBOutlet weak var childContentView: UIView!
16+
17+ @IBOutlet weak var mapContentView: UIView!
18+
19+ // MARK: - Peoperties
20+
21+ var reservation: Reservation?
22+
23+ var secondStepView: SecondStepView?
24+
25+ var mapView: MapImageScroll?
26+
27+ /// Как только получили ответ на запросах о бронирвоаниях, сразу обновляем
28+ var reservedIntervals: [ReservationPeriod] = [] {
29+ didSet {
30+ setupContainer(withReservedPeriods: reservedIntervals)
31+ }
32+ }
33+
34+ var reservationService: ReservationsService?
35+
36+ weak var coordinator: ChangeReservationCoordinator?
37+
38+ // MARK: - Buttons
39+
40+ var confirmButton: Button = {
41+ var button = Button()
42+ var style = BlackButtonStyle()
43+ style.apply(to: button, withTitle: "ПОДТВЕРДИТЬ")
44+ return button
45+ }()
46+
47+ // MARK: - Lifecycle
48+
49+ override func viewDidLoad() {
50+ super.viewDidLoad()
51+
52+ reservationService = ReservationsService(apiClient: APIClient.shared)
53+ setupButtons()
54+ setupMap()
55+ getReservations()
56+
57+ navigationItem.hidesBackButton = true
58+ // Do any additional setup after loading the view.
59+ }
60+
61+ // MARK: - setup
62+
63+ func setupButtons() {
64+ addStackViewWithButtons( rightBtn: confirmButton,
65+ constant: -childContentView.frame.height - 20)
66+
67+ confirmButton.addTarget(self, action: #selector(changeReservation), for: .touchUpInside)
68+ }
69+
70+ func setupContainer(withReservedPeriods resPer: [ReservationPeriod]) {
71+ secondStepView = SecondStepView.loadFromNib()
72+ childContentView.addSubviewThatFills(secondStepView)
73+
74+ guard let r = reservation else { return }
75+
76+ secondStepView?.bind(model: SecondStepModel(establishment: r.establishment,
77+ table: r.reservedTable,
78+ startTime: r.startTime,
79+ endTime: r.endTime,
80+ reservedintervals: resPer))
81+ }
82+
83+ func getReservations() {
84+ guard let r = reservation else { return }
85+ reservationService?.getAllReservations(establishmentID: r.establishment, completion: { (res) in
86+ switch res {
87+ case .failure(let err):
88+ self.displayAlert(forError: err, with: "Прости, не смогли загрузить доступные периоды для брони этого столика. Попробуй, пожалуйста, еще раз!")
89+ case .success(let allReservations):
90+ let isAdmin = DataStorage.standard.getUserModel()?.isAdmin ?? false
91+ let (start, end) = isAdmin ? r.startTime.getAdminStartingAndEndPoint() : r.startTime.getClientStartingAndEndPoint()
92+ let reservPeriods = HFunc.main.filterPeriodsStartEndDates(allReservations.reservations[r.reservedTable] ?? [],
93+ start,
94+ end)
95+
96+ self.reservedIntervals = reservPeriods
97+ }
98+ })
99+ }
100+
101+ func setupMap() {
102+ guard let reservation = reservation else {
103+ return
104+ }
105+
106+ let width = view.frame.width
107+ if reservation.establishment == 1 {
108+ mapView = MapView1.loadFromNib()
109+ mapView?.scrollViewParent.contentInset = UIEdgeInsets(top: 0,
110+ left: width / 2,
111+ bottom: 200,
112+ right: width / 2)
113+
114+ mapView?.scrollViewParent.setContentOffset(CGPoint(x: 0, y: 50), animated: false)
115+ } else {
116+ mapView = MapView2.loadFromNib()
117+ mapView?.scrollViewParent.setContentOffset(CGPoint(x: 0, y: -100), animated: false)
118+ mapView?.scrollViewParent.contentInset = UIEdgeInsets(top: 100,
119+ left: width / 2,
120+ bottom: 100,
121+ right: width / 2)
122+ }
123+
124+ mapContentView.addSubviewThatFills(mapView)
125+
126+ mapView?.isUserInteractionEnabled = false
127+ mapView?.scrollToTable(table: reservation.reservedTable)
128+ }
129+
130+ // MARK: - Handlers
131+
132+ @objc func changeReservation() {
133+ guard let r = secondStepView?.data, let uuid = reservation?.uuid else { return }
134+ confirmButton.loading = true
135+
136+ reservationService?.updateReservation(startTime: r.startTime,
137+ numberOfGuests: r.numberOfGuests,
138+ endTime: r.endTime,
139+ uuid: uuid,
140+ completion: { [weak self] (res) in
141+ if res {
142+ self?.coordinator?.finish(Reservation(uuid: uuid, reservationData: r))
143+ } else {
144+ self?.displayAlert(with: "Что-то пошло не так! Попробуешь еще раз?")
145+ }
146+
147+ self?.confirmButton.loading = false
148+ })
149+ }
150+
151+}
Hookah Tau/Controllers/Client/Tab bar/ClientTabbarCoordinator.swift+4
@@ -41,6 +41,10 @@ class ClientTabbarCoordinator: BaseCoordinator {
41 return { navigationController in
41 return { navigationController in
42 if navigationController.viewControllers.isEmpty {
42 if navigationController.viewControllers.isEmpty {
43 let profileCoordinator = ProfileCoordinator(navigationController: navigationController)
43 let profileCoordinator = ProfileCoordinator(navigationController: navigationController)
44+ profileCoordinator.didEndFlow = { [weak self, weak profileCoordinator] in
45+ self?.removeDependency(profileCoordinator)
46+ self?.didEndFlow?()
47+ }
44 self.addDependency(profileCoordinator)
48 self.addDependency(profileCoordinator)
45 profileCoordinator.start()
49 profileCoordinator.start()
46 }
50 }
DataStorage.swift → Hookah Tau/DB/DataStorage.swiftrenamed+46−1
@@ -6,7 +6,7 @@
6// Copyright © 2019 Daria Rednikina. All rights reserved.
6// Copyright © 2019 Daria Rednikina. All rights reserved.
7//
7//
8
8
9−import Foundation
9+import UIKit
10
10
11/// Класс для хранения промежуточного состояния регистрации,
11/// Класс для хранения промежуточного состояния регистрации,
12/// данных пользователя, ...
12/// данных пользователя, ...
@@ -17,6 +17,7 @@ class DataStorage {
17 case phone
17 case phone
18 case isAdmin
18 case isAdmin
19 case loggedIn
19 case loggedIn
20+ case cookies
20 }
21 }
21
22
22 private init() {}
23 private init() {}
@@ -41,6 +42,43 @@ class DataStorage {
41 UserDefaults.standard.setValue(isAdmin, forKey: Keys.isAdmin.rawValue)
42 UserDefaults.standard.setValue(isAdmin, forKey: Keys.isAdmin.rawValue)
42 }
43 }
43
44
45+
46+ /// Метод для установки куков в хранилище
47+ /// - Parameter cookies: куки
48+ /// - Parameter url: url для куков
49+ func setCookies(_ cookies: [HTTPCookie], forURL url: URL) {
50+ let cookiesStorage = HTTPCookieStorage.shared
51+ let userDefaults = UserDefaults.standard
52+
53+ var cookieDict = [String: AnyObject]()
54+
55+ for cookie in cookiesStorage.cookies(for: url)! {
56+ cookieDict[cookie.name] = cookie.properties as AnyObject?
57+ }
58+
59+ userDefaults.set(cookieDict, forKey: Keys.cookies.rawValue)
60+ }
61+
62+
63+ /// Достаем из хранилища и устанавливаем куки
64+ /// Если не выходит, то вовзращаем false
65+ func getCookies() -> Bool {
66+ let cookiesStorage = HTTPCookieStorage.shared
67+ let userDefaults = UserDefaults.standard
68+
69+ if let cookieDictionary = userDefaults.dictionary(forKey: Keys.cookies.rawValue) {
70+
71+ for (_, cookieProperties) in cookieDictionary {
72+ if let cookie = HTTPCookie(properties: cookieProperties as! [HTTPCookiePropertyKey : Any] ) {
73+ cookiesStorage.setCookie(cookie)
74+ }
75+ }
76+ return true
77+ }
78+
79+ return false
80+ }
81+
44 func getUserModel() -> User? {
82 func getUserModel() -> User? {
45 guard
83 guard
46 let name = UserDefaults.standard.string(forKey: Keys.name.rawValue),
84 let name = UserDefaults.standard.string(forKey: Keys.name.rawValue),
@@ -52,4 +90,11 @@ class DataStorage {
52 return User(name: name, phoneNumber: phone, isAdmin: isAdmin)
90 return User(name: name, phoneNumber: phone, isAdmin: isAdmin)
53 }
91 }
54
92
93+ func isLoggedIn() -> Bool {
94+ return UserDefaults.standard.bool(forKey: Keys.loggedIn.rawValue) && getCookies()
95+ }
96+
97+ func setLoggedInState(_ value: Bool) {
98+ UserDefaults.standard.set(value, forKey: Keys.loggedIn.rawValue)
99+ }
55}
100}
Hookah Tau/DB/TotalStorage.swiftnew file+124
@@ -0,0 +1,124 @@
1+//
2+// TotalStorage.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 28/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+/// Класс для хранения `establishments`,
12+class TotalStorage {
13+
14+ // MARK: - properties
15+
16+ static let standard = TotalStorage()
17+
18+ // MARK: - Init
19+
20+ private init() {
21+ service = EstablishmentSevice(apiClient: APIClient.shared)
22+ setEstablishments()
23+ }
24+
25+ // MARK: - getters
26+
27+ func getEstablishment(_ id: Int) -> EstablishmentData? {
28+ return establishments[id]
29+ }
30+
31+ func getTable(establishment eId: Int, table tId: Int) -> Table? {
32+ return imagesForTables[eId]?[tId]
33+ }
34+
35+ // MARK: - Setters
36+
37+ private func setEstablishments() {
38+ service.loadAdmins { (result) in
39+ switch result {
40+ case .success(let phones):
41+ self.phones = phones
42+ default:
43+ break
44+ }
45+ }
46+ }
47+
48+ // MARK: - Private
49+
50+ private let service: EstablishmentSevice
51+
52+ private var establishments: [Int: EstablishmentData] = [
53+ 1: EstablishmentData(id: 1,
54+ image: #imageLiteral(resourceName: "1"),
55+ admin: "",
56+ address: "Гороховский пер. 12с5, 205",
57+ maxTableNumber: 8),
58+
59+ 2: EstablishmentData(id: 2,
60+ image: #imageLiteral(resourceName: "2"),
61+ admin: "",
62+ address: "ул. Рыбинская 7, кв. 2",
63+ maxTableNumber: 7)
64+ ]
65+
66+ private var imagesForTables: [Int: [Int: Table]] = [
67+ 1 :[
68+ 1: Table(image: #imageLiteral(resourceName: "1_1"), maxGuestNumber: 6),
69+ 2: Table(image: #imageLiteral(resourceName: "1_2"), maxGuestNumber: 8),
70+ 3: Table(image: #imageLiteral(resourceName: "1_3"), maxGuestNumber: 8),
71+ 4: Table(image: #imageLiteral(resourceName: "1_4"), maxGuestNumber: 6),
72+ 5: Table(image: #imageLiteral(resourceName: "1_5"), maxGuestNumber: 6),
73+ 6: Table(image: #imageLiteral(resourceName: "1_6"), maxGuestNumber: 6),
74+ 7: Table(image: #imageLiteral(resourceName: "1_7"), maxGuestNumber: 6),
75+ 8: Table(image: #imageLiteral(resourceName: "1_8"), maxGuestNumber: 2)
76+ ],
77+ 2 :[
78+ 2: Table(image: #imageLiteral(resourceName: "2_2"), maxGuestNumber: 9),
79+ 3: Table(image: #imageLiteral(resourceName: "2_3"), maxGuestNumber: 6),
80+ 4: Table(image: #imageLiteral(resourceName: "2_4"), maxGuestNumber: 2),
81+ 5: Table(image: #imageLiteral(resourceName: "2_5"), maxGuestNumber: 5),
82+ 6: Table(image: #imageLiteral(resourceName: "2_6"), maxGuestNumber: 5),
83+ 7: Table(image: #imageLiteral(resourceName: "2_7"), maxGuestNumber: 5),
84+ 8: Table(image: #imageLiteral(resourceName: "2_8"), maxGuestNumber: 2)
85+ ]
86+ ]
87+
88+ private var phones: [Int: String] = [:] {
89+ didSet {
90+ let newEstablishments = phones.compactMap { el -> (Int, EstablishmentData)? in
91+ if let es = establishments[el.key] {
92+
93+ return (el.key, EstablishmentData(id: es.id,
94+ image: es.image,
95+ admin: el.value,
96+ address: es.address,
97+ maxTableNumber: es.maxTableNumber))
98+ } else {
99+ return nil
100+ }
101+ }
102+
103+ establishments = Dictionary(uniqueKeysWithValues: newEstablishments)
104+ }
105+ }
106+}
107+
108+// MARK: - Nested types
109+
110+extension TotalStorage {
111+
112+ struct EstablishmentData {
113+ var id: Int
114+ var image: UIImage
115+ var admin: String
116+ var address: String
117+ var maxTableNumber: Int
118+ }
119+
120+ struct Table {
121+ var image: UIImage
122+ var maxGuestNumber: Int
123+ }
124+}
Hookah Tau/Extensions+Date.swiftnew file+237
@@ -0,0 +1,237 @@
1+//
2+// Extensions+Date.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 16/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+struct IntervalDate {
12+ var day: Int
13+ var month: Int
14+ var year: Int
15+
16+ var minutes: Int? = nil
17+}
18+
19+extension DateFormatter {
20+ static let iso8601Full: DateFormatter = {
21+ let formatter = DateFormatter()
22+ formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
23+ formatter.timeZone = TimeZone(abbreviation: "UTC")
24+ return formatter
25+ }()
26+
27+ static let dmy: DateFormatter = {
28+ let formatter = DateFormatter()
29+ formatter.dateFormat = "yyyy-MM-dd"
30+ formatter.timeZone = TimeZone(abbreviation: "UTC")
31+ return formatter
32+ }()
33+}
34+
35+
36+extension Date {
37+ static func getNext(days: Int) -> [Date] {
38+ var result = [Date]()
39+
40+ var date = Date()
41+ let calendar = Calendar.current
42+
43+ for _ in 1...days {
44+ result.append(date)
45+
46+ let newDate = calendar.date(byAdding: .day, value: 1, to: date)
47+ guard let nextDate = newDate else { break }
48+ date = nextDate
49+ }
50+
51+ return result
52+ }
53+
54+ static func getDateFromCurrent(days: Int = 0, periods: Int? = nil) -> Date? {
55+ let date = Date()
56+
57+ let utcDate = date.getUTCDate()
58+
59+ let newDate = Calendar.current.date(byAdding: .day, value: days, to: utcDate)
60+
61+ // case if periods are important
62+ if let minutes = periods, let date = newDate {
63+ return date.changeTime(periods: minutes)
64+ }
65+
66+ return newDate
67+ }
68+
69+ /// Get UTC format of date
70+ func getUTCDate() -> Date {
71+ let calendar = Calendar.current
72+
73+ let day = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: self)
74+
75+ var dateCalendars = DateComponents()
76+ dateCalendars.hour = day.hour!
77+ dateCalendars.minute = day.minute!
78+ dateCalendars.day = day.day!
79+ dateCalendars.month = day.month!
80+ dateCalendars.year = day.year!
81+ dateCalendars.timeZone = TimeZone(abbreviation: "GMT")
82+
83+ return Calendar.current.date(from: dateCalendars)!
84+ }
85+
86+ func changeTime(periods: Int) -> Date? {
87+ let hours = (periods * 10 / 60) % 24
88+ let min = (periods * 10) % 60
89+
90+ return self.set(hours: hours, minutes: min, seconds: 0)
91+ }
92+
93+ func getDay() -> Int {
94+ let day = Calendar.current.dateComponents([.day], from: self)
95+ return day.day ?? 0
96+ }
97+
98+ func getDMY() -> Date {
99+ return set(hours: 0, minutes: 0, seconds: 0)!
100+ }
101+
102+ func addHours(_ h: Int) -> Date {
103+ return self.addingTimeInterval(Double(h) * 60.0 * 60.0)
104+ }
105+
106+ func addPeriods(_ p: Int) -> Date {
107+ let h = (p * 10 / 60) % 24
108+ let m = (p * 10) % 60
109+
110+ return self.addingTimeInterval(Double(h) * 60.0 * 60.0 + Double(m) * 60.0)
111+ }
112+
113+ func set(hours: Int, minutes: Int, seconds: Int) -> Date? {
114+
115+ let dateFormatter = DateFormatter()
116+ dateFormatter.calendar = Calendar.current
117+ dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
118+ dateFormatter.dateFormat = "yyyy-MM-dd"
119+
120+ let newDateString = "\(dateFormatter.string(from: self)) \(hours):\(minutes):\(seconds)"
121+
122+ dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
123+
124+ return dateFormatter.date(from: newDateString)
125+ }
126+
127+ func getMinutesPeriods(fromStart startDate: Date) -> Int {
128+ let diffInMins = Calendar.current.dateComponents([.minute], from: startDate, to: self).minute!
129+ let periods = diffInMins / 10
130+ return periods
131+ }
132+
133+ func getPrevCurrentNextMonth() -> (String, String, String) {
134+ let dateFormatter = DateFormatter()
135+ dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
136+ dateFormatter.dateFormat = "LLLL"
137+ let current = dateFormatter.string(from: self)
138+
139+ let nextDate = Calendar.current.date(byAdding: .month, value: 1, to: self)!
140+ let next = dateFormatter.string(from: nextDate)
141+
142+ let prevDate = Calendar.current.date(byAdding: .month, value: -1, to: self)!
143+ let prev = dateFormatter.string(from: prevDate)
144+
145+ print("\(prevDate) \(self) \(nextDate)")
146+ return (prev, current, next)
147+ }
148+}
149+
150+// MARK: - Admin vs Client
151+
152+extension Date {
153+
154+ /// Идем на день назад, чтобы найти точку начала с которой может забронировать администратор
155+ func getAdminStartingAndEndPoint() -> (Date, Date) {
156+ let utcDate = self.getUTCDate()
157+
158+ let startDate = Calendar.current.date(byAdding: .day, value: -1, to: utcDate)!
159+ let endDate = Calendar.current.date(byAdding: .day, value: 1, to: utcDate)!
160+
161+ return (startDate, endDate)
162+ }
163+
164+ func getAdminsStartingPoint() -> Int {
165+ var calendar = Calendar.current
166+ calendar.timeZone = TimeZone(abbreviation: "UTC")!
167+
168+ let comp = calendar.dateComponents([.hour, .minute], from: self)
169+ return (comp.hour! * 6 + comp.minute! / 10)
170+ }
171+
172+ func getClientStartingAndEndPoint() -> (Date, Date) {
173+ // час
174+ var calendar = Calendar.current
175+ calendar.timeZone = TimeZone(abbreviation: "UTC")!
176+
177+ let hour = calendar.dateComponents([.hour], from: self).hour!
178+
179+ if hour >= 0 && hour <= 3 { // [ 00:00 ... 3:00 ]
180+ let endDate = self.set(hours: 3, minutes: 0, seconds: 0)! // 3 00
181+ let start = calendar.date(byAdding: .day, value: -1, to: self)!
182+ let startDate = start.set(hours: 12, minutes: 0, seconds: 0)! // 12 00
183+
184+ return (startDate, endDate)
185+ } else { // [12:00 ... 23:50]
186+ let startDate = self.set(hours: 12, minutes: 0, seconds: 0)! // 12 00
187+ let end = calendar.date(byAdding: .day, value: 1, to: self)!
188+ let endDate = end.set(hours: 3, minutes: 0, seconds: 0)! // 3 00
189+
190+ return (startDate, endDate)
191+ }
192+ }
193+
194+ /// Определяем попадает ли в промежуток между [3:00, 12:00)
195+ func isInClosingHours() -> Bool {
196+ var calendar = Calendar.current
197+ calendar.timeZone = TimeZone(abbreviation: "UTC")!
198+
199+ let day = calendar.dateComponents([.hour, .day, .month, .year, .minute], from: self)
200+
201+ var dateCalendars = DateComponents()
202+ dateCalendars.hour = 3
203+ dateCalendars.minute = 0
204+ dateCalendars.day = day.day!
205+ dateCalendars.month = day.month!
206+ dateCalendars.year = day.year!
207+ dateCalendars.timeZone = TimeZone(abbreviation: "GMT")
208+
209+ let startClosing = calendar.date(from: dateCalendars)!
210+
211+ dateCalendars.hour = 11
212+ dateCalendars.minute = 50
213+
214+ let endClosing = calendar.date(from: dateCalendars)!
215+
216+ let intervalClosing = DateInterval(start: startClosing, end: endClosing)
217+
218+ return intervalClosing.contains(self)
219+ }
220+}
221+
222+extension Date {
223+ static func format(_ startDate: Date, _ endDate: Date) -> (date: String, time: String) {
224+ let dateFormatter = DateFormatter()
225+ dateFormatter.calendar = Calendar.current
226+ dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
227+ dateFormatter.dateFormat = "d MMMM"
228+ dateFormatter.locale = Locale(identifier: "ru_RU")
229+
230+ let dateStr = "\(dateFormatter.string(from: startDate))"
231+
232+ dateFormatter.dateFormat = "HH:mm"
233+ let timeStr = "\(dateFormatter.string(from: startDate)) — \(dateFormatter.string(from: endDate))"
234+
235+ return (dateStr, timeStr)
236+ }
237+}
Hookah Tau/Extensions+UIView.swift+16
@@ -59,6 +59,22 @@ extension UIView {
59 setNeedsLayout()
59 setNeedsLayout()
60 layoutIfNeeded()
60 layoutIfNeeded()
61 }
61 }
62+
63+ func centerSubview(_ view: UIView?) {
64+ guard let view = view else {
65+ assert(false, "View mustn't be nil")
66+ return
67+ }
68+
69+ view.translatesAutoresizingMaskIntoConstraints = false
70+ addSubview(view)
71+
72+ view.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
73+ view.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
74+
75+ setNeedsLayout()
76+ layoutIfNeeded()
77+ }
62}
78}
63
79
64
80
Hookah Tau/Extenstions+IBDesignable.swiftnew file+25
@@ -0,0 +1,25 @@
1+//
2+// Extenstions+IBDesignable.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 16/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import UIKit
10+
11+@IBDesignable class RadialGradientView: UIView {
12+
13+ @IBInspectable var outsideColor: UIColor = UIColor.red
14+ @IBInspectable var insideColor: UIColor = UIColor.clear.withAlphaComponent(0)
15+
16+ override func draw(_ rect: CGRect) {
17+ let colors = [insideColor.cgColor, outsideColor.cgColor] as CFArray
18+ let endRadius = sqrt(pow(frame.width/2, 2) + pow(frame.height/2, 2))
19+ let center = CGPoint(x: bounds.size.width / 2, y: bounds.size.height / 2)
20+ let gradient = CGGradient(colorsSpace: nil, colors: colors, locations: nil)
21+ let context = UIGraphicsGetCurrentContext()
22+
23+ context?.drawRadialGradient(gradient!, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: endRadius, options: CGGradientDrawingOptions.drawsBeforeStartLocation)
24+ }
25+}
Hookah Tau/HFunc.swiftnew file+61
@@ -0,0 +1,61 @@
1+//
2+// HFunc.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 02/12/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+
12+class HFunc {
13+
14+ private init() {}
15+
16+ static let main = HFunc()
17+
18+
19+ /// Filtering function to get every periods which intersects with given date
20+ /// - Parameter periods: all periods of bookings (for a particular table)
21+ /// - Parameter today: date
22+ func filterPeriodsInDate(_ periods: [ReservationPeriod], _ today: Date) -> [ReservationPeriod] {
23+ return periods.filter(filterPeriod(today))
24+ }
25+
26+
27+ /// Filtering func to get every intersecting period for the table. Useful for 2nd booning screen
28+ /// - Parameter periods: Periods for the table
29+ /// - Parameter start: for client 12:00, for admin t - 24h
30+ /// - Parameter end: for client 3:00, for admin t + 24h
31+ func filterPeriodsStartEndDates(_ periods: [ReservationPeriod], _ start: Date, _ end: Date) -> [ReservationPeriod] {
32+ return periods.filter(filterInInterval(start, end))
33+ }
34+
35+ private func filterPeriod(_ today: Date) -> ((ReservationPeriod) -> Bool) {
36+
37+ func datePredicate(_ start: Date, _ end: Date, _ current: Date) -> Bool {
38+ var calendar = Calendar.current
39+ calendar.timeZone = TimeZone(identifier: "GMT")!
40+
41+ let result = calendar.isDate(start, equalTo: current, toGranularity: .day)
42+ || calendar.isDate(end, equalTo: current, toGranularity: .day)
43+
44+ return result
45+ }
46+
47+ return { (period: ReservationPeriod) in datePredicate(period.startTime, period.endTime, today) }
48+ }
49+
50+ private func filterInInterval(_ start: Date, _ end: Date) -> ((ReservationPeriod) -> Bool) {
51+
52+ let dateInterval = DateInterval(start: start, end: end)
53+ func intervalChecking(_ sp: Date, _ ep: Date) -> Bool {
54+ let innerInterval = DateInterval(start: sp, end: ep)
55+
56+ return dateInterval.intersects(innerInterval)
57+ }
58+
59+ return { (period: ReservationPeriod) in intervalChecking(period.startTime, period.endTime) }
60+ }
61+}
Hookah Tau/Models/AllReservations.swiftnew file+39
@@ -0,0 +1,39 @@
1+//
2+// AllReservations.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 15/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+struct AllReservations: MyCodable {
12+ var reservations: [Int: [ReservationPeriod]]
13+ var intervals: [Date: [Int]]
14+
15+ enum CodingKeys: CodingKey {
16+ case reservations
17+ case intervals
18+ }
19+
20+ init(from decoder: Decoder) throws {
21+ let container = try decoder.container(keyedBy: CodingKeys.self)
22+
23+ let intervalsWithStr = try container.decode([String: [Int]].self, forKey: .intervals)
24+ reservations = try container.decode([Int: [ReservationPeriod]].self, forKey: .reservations)
25+
26+ let intervArray = intervalsWithStr.map { (element) -> (Date, [Int]) in
27+ let key = DateFormatter.iso8601Full.date(from: element.key)!
28+ return (key, element.value)
29+ }
30+
31+ intervals = Dictionary(uniqueKeysWithValues: intervArray)
32+ }
33+}
34+
35+struct ReservationPeriod: MyCodable {
36+ var startTime: Date
37+ var duration: Int
38+ var endTime: Date
39+}
Hookah Tau/Models/Reservation.swiftnew file+49
@@ -0,0 +1,49 @@
1+//
2+// Reservation.swift
3+// Hookah Tau
4+//
5+// Created by cstore on 06/11/2019.
6+// Copyright © 2019 Daria Rednikina. All rights reserved.
7+//
8+
9+import Foundation
10+
11+
12+struct Reservation: MyCodable {
13+
14+ var uuid: String
15+ var establishment: Int
16+ var startTime: Date
17+ var endTime: Date
18+ var numberOfGuests: Int
19+ var reservedTable: Int
20+
21+ init(uuid: String, reservationData: ReservationData) {
22+ self.uuid = uuid
23+ self.establishment = reservationData.establishment
24+ self.startTime = reservationData.startTime
25+ self.endTime = reservationData.endTime
26+ self.numberOfGuests = reservationData.numberOfGuests
27+ self.reservedTable = reservationData.reservedTable
28+ }
29+
30+ init(uuid: String, establishment: Int, startTime: Date, endTime: Date, numberOfGuests: Int, reservedTable: Int) {
31+ self.uuid = uuid
32+ self.establishment = establishment
33+ self.startTime = startTime
34+ self.endTime = endTime
35+ self.numberOfGuests = numberOfGuests
36+ self.reservedTable = reservedTable
37+ }
38+}
39+
40+/// `Reservation` without `uuid`
41+struct ReservationData: MyCodable {
42+
43+ var establishment: Int
44+ var startTime: Date
45+ var endTime: Date
46+ var numberOfGuests: Int
47+ var reservedTable: Int
48+
49+}
Hookah Tau/Supporting Files/Assets.xcassets/1.imageset/Contents.jsonnew file+15
@@ -0,0 +1,15 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "place 1.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ },
12+ "properties" : {
13+ "preserves-vector-representation" : true
14+ }
15+}
Hookah Tau/Supporting Files/Assets.xcassets/1.imageset/place 1.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_1.imageset/1_1.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_1.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "1_1.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/1_2.imageset/1_2.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_2.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "1_2.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/1_3.imageset/1_3.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_3.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "1_3.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/1_4.imageset/1_4.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_4.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "1_4.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/1_5.imageset/1_5.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_5.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "1_5.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/1_6.imageset/1_6.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_6.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "1_6.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/1_7.imageset/1_7.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_7.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "1_7.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/1_8.imageset/1_8.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/1_8.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "1_8.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/2.imageset/Contents.jsonnew file+15
@@ -0,0 +1,15 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "place 2.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ },
12+ "properties" : {
13+ "preserves-vector-representation" : true
14+ }
15+}
Hookah Tau/Supporting Files/Assets.xcassets/2.imageset/place 2.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/2_2.imageset/2_2.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/2_2.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "2_2.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/2_3.imageset/2_3.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/2_3.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "2_3.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/2_4.imageset/2_4.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/2_4.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "2_4.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/2_5.imageset/2_5.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/2_5.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "2_5.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/2_6.imageset/2_6.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/2_6.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "2_6.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/2_7.imageset/2_7.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/2_7.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "2_7.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/2_8.imageset/2_8.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/2_8.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "2_8.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/Map.imageset/Contents.json → Hookah Tau/Supporting Files/Assets.xcassets/Group.imageset/Contents.jsonrenamed+1−1
@@ -2,7 +2,7 @@
2 "images" : [
2 "images" : [
3 {
3 {
4 "idiom" : "universal",
4 "idiom" : "universal",
5− "filename" : "Map.pdf"
5+ "filename" : "Group.pdf"
6 }
6 }
7 ],
7 ],
8 "info" : {
8 "info" : {
Hookah Tau/Supporting Files/Assets.xcassets/Group.imageset/Group.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/Map.imageset/Map.pdfdeleted

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/Tick.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "Path.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/Tick.imageset/Path.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/TriangleDown.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "Triangle.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/TriangleDown.imageset/Triangle.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/TriangleUp.imageset/Contents.jsonnew file+12
@@ -0,0 +1,12 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "TriangleUp.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ }
12+}
Hookah Tau/Supporting Files/Assets.xcassets/TriangleUp.imageset/TriangleUp.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/handle_left.imageset/Contents.jsonnew file+15
@@ -0,0 +1,15 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "handle.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ },
12+ "properties" : {
13+ "preserves-vector-representation" : true
14+ }
15+}
Hookah Tau/Supporting Files/Assets.xcassets/handle_left.imageset/handle.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/map_1.imageset/Contents.jsonnew file+15
@@ -0,0 +1,15 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "map_1.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ },
12+ "properties" : {
13+ "preserves-vector-representation" : true
14+ }
15+}
Hookah Tau/Supporting Files/Assets.xcassets/map_1.imageset/map_1.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/map_2.imageset/Contents.jsonnew file+15
@@ -0,0 +1,15 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "place 2.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ },
12+ "properties" : {
13+ "preserves-vector-representation" : true
14+ }
15+}
Hookah Tau/Supporting Files/Assets.xcassets/map_2.imageset/place 2.pdfnew file

Binary file not shown.

Hookah Tau/Supporting Files/Assets.xcassets/phone.imageset/Contents.jsonnew file+15
@@ -0,0 +1,15 @@
1+{
2+ "images" : [
3+ {
4+ "idiom" : "universal",
5+ "filename" : "Medium-M.pdf"
6+ }
7+ ],
8+ "info" : {
9+ "version" : 1,
10+ "author" : "xcode"
11+ },
12+ "properties" : {
13+ "preserves-vector-representation" : true
14+ }
15+}
Hookah Tau/Supporting Files/Assets.xcassets/phone.imageset/Medium-M.pdfnew file

Binary file not shown.