git.iko.soy/dashared/GDproject
on caebb61 help sign in
Cartfile+1−2
since splitsnapshots
unifiedsplit
@@ -5,5 +5,4 @@ github "macteo/Marklight"
5github "Alamofire/Alamofire" "5.0.0-beta.5"
5github "Alamofire/Alamofire" "5.0.0-beta.5"
6github "52inc/Pulley"
6github "52inc/Pulley"
7github "HeroTransitions/Hero"
7github "HeroTransitions/Hero"
8−github "ReactiveCocoa/ReactiveCocoa" ~> 9.0
8+github "ReactiveCocoa/ReactiveCocoa" ~> 9.0
9−github "ZaidSA/TaggerKit" "bb826a7"
GDproject.xcodeproj/project.pbxproj+12−54
@@ -8,36 +8,27 @@
8
8
9/* Begin PBXBuildFile section */
9/* Begin PBXBuildFile section */
10 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */; };
10 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */; };
11− 121A8972226B1EAC005EE599 /* TagsSuggestionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */; };
11+ 121A8972226B1EAC005EE599 /* AnonimousChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */; };
12− 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */; };
13− 123589FD22899339002F8028 /* MessageViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123589FC22899339002F8028 /* MessageViewCell.swift */; };
14 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
12 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
15 123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
13 123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
16 124CC7032221C00C009DF531 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124CC7022221C00C009DF531 /* Model.swift */; };
14 124CC7032221C00C009DF531 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124CC7022221C00C009DF531 /* Model.swift */; };
17− 125A9A8A2285C3DA00513E2A /* CodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A892285C3DA00513E2A /* CodeViewController.swift */; };
18− 125A9A8E2286068A00513E2A /* RegisterTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */; };
19− 125A9A90228609C500513E2A /* InititalsViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A8F228609C500513E2A /* InititalsViewCell.swift */; };
20− 125A9A922286100800513E2A /* FacultyTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A912286100800513E2A /* FacultyTableViewController.swift */; };
21 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57C22171D2A008A3575 /* ProfileViewController.swift */; };
15 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57C22171D2A008A3575 /* ProfileViewController.swift */; };
22 125BD57F22171D73008A3575 /* Extentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57E22171D73008A3575 /* Extentions.swift */; };
16 125BD57F22171D73008A3575 /* Extentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57E22171D73008A3575 /* Extentions.swift */; };
23 125BD5812217314A008A3575 /* NewsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD5802217314A008A3575 /* NewsVC.swift */; };
17 125BD5812217314A008A3575 /* NewsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD5802217314A008A3575 /* NewsVC.swift */; };
24 1261BB93227B364C003898CF /* ChannelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB92227B364C003898CF /* ChannelViewController.swift */; };
18 1261BB93227B364C003898CF /* ChannelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB92227B364C003898CF /* ChannelViewController.swift */; };
25 1261BB95227B3991003898CF /* AddToChannelVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB94227B3991003898CF /* AddToChannelVC.swift */; };
19 1261BB95227B3991003898CF /* AddToChannelVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB94227B3991003898CF /* AddToChannelVC.swift */; };
26− 1261BB9E227B793D003898CF /* ChatInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB9D227B793D003898CF /* ChatInfoViewController.swift */; };
27− 12758257227F1401001F291F /* DialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12758256227F1401001F291F /* DialogViewController.swift */; };
28 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1288B5CD221F1158002BE6B1 /* DataStorage.swift */; };
20 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1288B5CD221F1158002BE6B1 /* DataStorage.swift */; };
29 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */; };
21 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */; };
30 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */; };
22 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */; };
23+ 1291BE3622218DBF009D3F23 /* LogInCoordinator1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE3522218DBF009D3F23 /* LogInCoordinator1.swift */; };
31 129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320032279B4270035C7B3 /* MessagesViewController.swift */; };
24 129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320032279B4270035C7B3 /* MessagesViewController.swift */; };
32 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320062279B5690035C7B3 /* MessagesCoordinator.swift */; };
25 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320062279B5690035C7B3 /* MessagesCoordinator.swift */; };
33 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */; };
26 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */; };
27+ 1293200B2279D02D0035C7B3 /* DialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1293200A2279D02D0035C7B3 /* DialogViewController.swift */; };
34 1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1293200C2279D7310035C7B3 /* CompletionTree.swift */; };
28 1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1293200C2279D7310035C7B3 /* CompletionTree.swift */; };
35− 1298810B227F13840032ACA3 /* DialogCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1298810A227F13840032ACA3 /* DialogCell.swift */; };
36 12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */; };
29 12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */; };
37 12BA4B9D224101E700DF93D7 /* BaseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */; };
30 12BA4B9D224101E700DF93D7 /* BaseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */; };
38 12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */; };
31 12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */; };
39− 12CE7D6F227B94B10024B6E8 /* TaggerKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */; };
40− 12CE7D71227B94B50024B6E8 /* TaggerKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
41 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D132221C321600B35452 /* ChannelListController.swift */; };
32 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D132221C321600B35452 /* ChannelListController.swift */; };
42 12D7D135221C42B700B35452 /* ChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D134221C42B700B35452 /* ChannelController.swift */; };
33 12D7D135221C42B700B35452 /* ChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D134221C42B700B35452 /* ChannelController.swift */; };
43 12D7D137221D78E800B35452 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D136221D78E800B35452 /* Channel.swift */; };
34 12D7D137221D78E800B35452 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D136221D78E800B35452 /* Channel.swift */; };
@@ -97,7 +88,6 @@
97 12FDAC92226B5E5400995B4E /* Pulley.framework in Embed Frameworks */,
88 12FDAC92226B5E5400995B4E /* Pulley.framework in Embed Frameworks */,
98 12FDAC8C226B5E4E00995B4E /* Hero.framework in Embed Frameworks */,
89 12FDAC8C226B5E4E00995B4E /* Hero.framework in Embed Frameworks */,
99 12FDAC90226B5E5200995B4E /* Marklight.framework in Embed Frameworks */,
90 12FDAC90226B5E5200995B4E /* Marklight.framework in Embed Frameworks */,
100− 12CE7D71227B94B50024B6E8 /* TaggerKit.framework in Embed Frameworks */,
101 12FDACA0226B9E7C00995B4E /* ReactiveCocoa.framework in Embed Frameworks */,
91 12FDACA0226B9E7C00995B4E /* ReactiveCocoa.framework in Embed Frameworks */,
102 );
92 );
103 name = "Embed Frameworks";
93 name = "Embed Frameworks";
@@ -107,35 +97,27 @@
107
97
108/* Begin PBXFileReference section */
98/* Begin PBXFileReference section */
109 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplifiedChannelsList.swift; sourceTree = "<group>"; };
99 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplifiedChannelsList.swift; sourceTree = "<group>"; };
110− 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsSuggestionController.swift; sourceTree = "<group>"; };
100+ 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnonimousChannelController.swift; sourceTree = "<group>"; };
111− 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaggsSelectionViewController.swift; sourceTree = "<group>"; };
112− 123589FC22899339002F8028 /* MessageViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewCell.swift; sourceTree = "<group>"; };
113 123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
101 123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
114 123E37A6221F1DD700F6E42A /* MainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
102 123E37A6221F1DD700F6E42A /* MainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
115 124CC7022221C00C009DF531 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
103 124CC7022221C00C009DF531 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
116− 125A9A892285C3DA00513E2A /* CodeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeViewController.swift; sourceTree = "<group>"; };
117− 125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterTableViewController.swift; sourceTree = "<group>"; };
118− 125A9A8F228609C500513E2A /* InititalsViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InititalsViewCell.swift; sourceTree = "<group>"; };
119− 125A9A912286100800513E2A /* FacultyTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FacultyTableViewController.swift; sourceTree = "<group>"; };
120 125BD57C22171D2A008A3575 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
104 125BD57C22171D2A008A3575 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
121 125BD57E22171D73008A3575 /* Extentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extentions.swift; sourceTree = "<group>"; };
105 125BD57E22171D73008A3575 /* Extentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extentions.swift; sourceTree = "<group>"; };
122 125BD5802217314A008A3575 /* NewsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsVC.swift; sourceTree = "<group>"; };
106 125BD5802217314A008A3575 /* NewsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsVC.swift; sourceTree = "<group>"; };
123 1261BB92227B364C003898CF /* ChannelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelViewController.swift; sourceTree = "<group>"; };
107 1261BB92227B364C003898CF /* ChannelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelViewController.swift; sourceTree = "<group>"; };
124 1261BB94227B3991003898CF /* AddToChannelVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddToChannelVC.swift; sourceTree = "<group>"; };
108 1261BB94227B3991003898CF /* AddToChannelVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddToChannelVC.swift; sourceTree = "<group>"; };
125− 1261BB9D227B793D003898CF /* ChatInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoViewController.swift; sourceTree = "<group>"; };
126− 12758256227F1401001F291F /* DialogViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DialogViewController.swift; sourceTree = "<group>"; };
127 1288B5CD221F1158002BE6B1 /* DataStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStorage.swift; sourceTree = "<group>"; };
109 1288B5CD221F1158002BE6B1 /* DataStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStorage.swift; sourceTree = "<group>"; };
128 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelsCoordinator.swift; sourceTree = "<group>"; };
110 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelsCoordinator.swift; sourceTree = "<group>"; };
129 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbarCoordinator.swift; sourceTree = "<group>"; };
111 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbarCoordinator.swift; sourceTree = "<group>"; };
112+ 1291BE3522218DBF009D3F23 /* LogInCoordinator1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInCoordinator1.swift; sourceTree = "<group>"; };
130 129320032279B4270035C7B3 /* MessagesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = "<group>"; };
113 129320032279B4270035C7B3 /* MessagesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = "<group>"; };
131 129320062279B5690035C7B3 /* MessagesCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesCoordinator.swift; sourceTree = "<group>"; };
114 129320062279B5690035C7B3 /* MessagesCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesCoordinator.swift; sourceTree = "<group>"; };
132 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PeopleToWriteViewController.swift; path = GDproject/Controller/Messages/PeopleToWriteViewController.swift; sourceTree = SOURCE_ROOT; };
115 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PeopleToWriteViewController.swift; path = GDproject/Controller/Messages/PeopleToWriteViewController.swift; sourceTree = SOURCE_ROOT; };
116+ 1293200A2279D02D0035C7B3 /* DialogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DialogViewController.swift; path = GDproject/Controller/Messages/DialogViewController.swift; sourceTree = SOURCE_ROOT; };
133 1293200C2279D7310035C7B3 /* CompletionTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionTree.swift; sourceTree = "<group>"; };
117 1293200C2279D7310035C7B3 /* CompletionTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionTree.swift; sourceTree = "<group>"; };
134− 1298810A227F13840032ACA3 /* DialogCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialogCell.swift; sourceTree = "<group>"; };
135 12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationCoordinator.swift; sourceTree = "<group>"; };
118 12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationCoordinator.swift; sourceTree = "<group>"; };
136 12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCoordinator.swift; sourceTree = "<group>"; };
119 12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCoordinator.swift; sourceTree = "<group>"; };
137 12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInCoordinator.swift; sourceTree = "<group>"; };
120 12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInCoordinator.swift; sourceTree = "<group>"; };
138− 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TaggerKit.framework; path = Carthage/Build/iOS/TaggerKit.framework; sourceTree = "<group>"; };
139 12D7D132221C321600B35452 /* ChannelListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelListController.swift; sourceTree = "<group>"; };
121 12D7D132221C321600B35452 /* ChannelListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelListController.swift; sourceTree = "<group>"; };
140 12D7D134221C42B700B35452 /* ChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelController.swift; sourceTree = "<group>"; };
122 12D7D134221C42B700B35452 /* ChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelController.swift; sourceTree = "<group>"; };
141 12D7D136221D78E800B35452 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
123 12D7D136221D78E800B35452 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
@@ -185,7 +167,6 @@
185 12FDAC7D226B5E2900995B4E /* Result.framework in Frameworks */,
167 12FDAC7D226B5E2900995B4E /* Result.framework in Frameworks */,
186 12FDAC9B226B652C00995B4E /* ReactiveSwift.framework in Frameworks */,
168 12FDAC9B226B652C00995B4E /* ReactiveSwift.framework in Frameworks */,
187 12FDAC7E226B5E2900995B4E /* Cartography.framework in Frameworks */,
169 12FDAC7E226B5E2900995B4E /* Cartography.framework in Frameworks */,
188− 12CE7D6F227B94B10024B6E8 /* TaggerKit.framework in Frameworks */,
189 12FDAC8B226B5E4E00995B4E /* Hero.framework in Frameworks */,
170 12FDAC8B226B5E4E00995B4E /* Hero.framework in Frameworks */,
190 );
171 );
191 runOnlyForDeploymentPostprocessing = 0;
172 runOnlyForDeploymentPostprocessing = 0;
@@ -224,11 +205,8 @@
224 1291BE3722218DC4009D3F23 /* Log In */ = {
205 1291BE3722218DC4009D3F23 /* Log In */ = {
225 isa = PBXGroup;
206 isa = PBXGroup;
226 children = (
207 children = (
227− 125A9A912286100800513E2A /* FacultyTableViewController.swift */,
228− 125A9A8F228609C500513E2A /* InititalsViewCell.swift */,
229− 125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */,
230− 125A9A892285C3DA00513E2A /* CodeViewController.swift */,
231 123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
208 123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
209+ 1291BE3522218DBF009D3F23 /* LogInCoordinator1.swift */,
232 );
210 );
233 path = "Log In";
211 path = "Log In";
234 sourceTree = "<group>";
212 sourceTree = "<group>";
@@ -236,28 +214,16 @@
236 129320052279B4300035C7B3 /* Messages */ = {
214 129320052279B4300035C7B3 /* Messages */ = {
237 isa = PBXGroup;
215 isa = PBXGroup;
238 children = (
216 children = (
239− 1261BB9D227B793D003898CF /* ChatInfoViewController.swift */,
240 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */,
217 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */,
241− 1298810C227F138C0032ACA3 /* Dialog */,
218+ 1293200A2279D02D0035C7B3 /* DialogViewController.swift */,
242 129320032279B4270035C7B3 /* MessagesViewController.swift */,
219 129320032279B4270035C7B3 /* MessagesViewController.swift */,
243− 123589FC22899339002F8028 /* MessageViewCell.swift */,
244 );
220 );
245 path = Messages;
221 path = Messages;
246 sourceTree = "<group>";
222 sourceTree = "<group>";
247 };
223 };
248− 1298810C227F138C0032ACA3 /* Dialog */ = {
249− isa = PBXGroup;
250− children = (
251− 12758256227F1401001F291F /* DialogViewController.swift */,
252− 1298810A227F13840032ACA3 /* DialogCell.swift */,
253− );
254− path = Dialog;
255− sourceTree = "<group>";
256− };
257 12E36D8F221424EA006FCDD7 = {
224 12E36D8F221424EA006FCDD7 = {
258 isa = PBXGroup;
225 isa = PBXGroup;
259 children = (
226 children = (
260− 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */,
261 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */,
227 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */,
262 12FDAC99226B652400995B4E /* ReactiveSwift.framework */,
228 12FDAC99226B652400995B4E /* ReactiveSwift.framework */,
263 12FDAC95226B61C400995B4E /* TinyConstraints.framework */,
229 12FDAC95226B61C400995B4E /* TinyConstraints.framework */,
@@ -336,10 +302,9 @@
336 isa = PBXGroup;
302 isa = PBXGroup;
337 children = (
303 children = (
338 1261BB92227B364C003898CF /* ChannelViewController.swift */,
304 1261BB92227B364C003898CF /* ChannelViewController.swift */,
339− 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */,
340 1261BB94227B3991003898CF /* AddToChannelVC.swift */,
305 1261BB94227B3991003898CF /* AddToChannelVC.swift */,
341 12D7D134221C42B700B35452 /* ChannelController.swift */,
306 12D7D134221C42B700B35452 /* ChannelController.swift */,
342− 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */,
307+ 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */,
343 12D7D132221C321600B35452 /* ChannelListController.swift */,
308 12D7D132221C321600B35452 /* ChannelListController.swift */,
344 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */,
309 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */,
345 12E36DC922144635006FCDD7 /* NewPostViewController.swift */,
310 12E36DC922144635006FCDD7 /* NewPostViewController.swift */,
@@ -437,36 +402,29 @@
437 files = (
402 files = (
438 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */,
403 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */,
439 124CC7032221C00C009DF531 /* Model.swift in Sources */,
404 124CC7032221C00C009DF531 /* Model.swift in Sources */,
440− 125A9A90228609C500513E2A /* InititalsViewCell.swift in Sources */,
441− 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */,
442 12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */,
405 12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */,
443 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
406 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
444 12D7D137221D78E800B35452 /* Channel.swift in Sources */,
407 12D7D137221D78E800B35452 /* Channel.swift in Sources */,
408+ 1291BE3622218DBF009D3F23 /* LogInCoordinator1.swift in Sources */,
445 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */,
409 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */,
446 125BD5812217314A008A3575 /* NewsVC.swift in Sources */,
410 125BD5812217314A008A3575 /* NewsVC.swift in Sources */,
447 12E36DB72214400A006FCDD7 /* Post.swift in Sources */,
411 12E36DB72214400A006FCDD7 /* Post.swift in Sources */,
448 12DB7FDF221877160096878E /* InviteViewController.swift in Sources */,
412 12DB7FDF221877160096878E /* InviteViewController.swift in Sources */,
449− 121A8972226B1EAC005EE599 /* TagsSuggestionController.swift in Sources */,
413+ 121A8972226B1EAC005EE599 /* AnonimousChannelController.swift in Sources */,
450 1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */,
414 1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */,
415+ 1293200B2279D02D0035C7B3 /* DialogViewController.swift in Sources */,
451 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */,
416 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */,
452− 1261BB9E227B793D003898CF /* ChatInfoViewController.swift in Sources */,
453 12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */,
417 12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */,
454− 1298810B227F13840032ACA3 /* DialogCell.swift in Sources */,
455− 125A9A922286100800513E2A /* FacultyTableViewController.swift in Sources */,
456− 125A9A8E2286068A00513E2A /* RegisterTableViewController.swift in Sources */,
457− 123589FD22899339002F8028 /* MessageViewCell.swift in Sources */,
458 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */,
418 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */,
459 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */,
419 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */,
460 125BD57F22171D73008A3575 /* Extentions.swift in Sources */,
420 125BD57F22171D73008A3575 /* Extentions.swift in Sources */,
461 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */,
421 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */,
462− 125A9A8A2285C3DA00513E2A /* CodeViewController.swift in Sources */,
463 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */,
422 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */,
464 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */,
423 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */,
465 12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */,
424 12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */,
466 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */,
425 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */,
467 12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */,
426 12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */,
468 129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */,
427 129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */,
469− 12758257227F1401001F291F /* DialogViewController.swift in Sources */,
470 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */,
428 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */,
471 12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */,
429 12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */,
472 12F3D6B22241097B00A69214 /* ProfileCoordinator.swift in Sources */,
430 12F3D6B22241097B00A69214 /* ProfileCoordinator.swift in Sources */,
GDproject/Base.lproj/Main.storyboard+47−451
@@ -11,11 +11,11 @@
11 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
11 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
12 </dependencies>
12 </dependencies>
13 <scenes>
13 <scenes>
14− <!--Chats-->
14+ <!--Item-->
15 <scene sceneID="bZ2-fw-XBE">
15 <scene sceneID="bZ2-fw-XBE">
16 <objects>
16 <objects>
17 <navigationController id="gt4-mD-66Q" sceneMemberID="viewController">
17 <navigationController id="gt4-mD-66Q" sceneMemberID="viewController">
18− <tabBarItem key="tabBarItem" title="Chats" image="chat" id="ZPm-j1-3dy"/>
18+ <tabBarItem key="tabBarItem" title="Item" id="ZPm-j1-3dy"/>
19 <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="XiY-wd-750">
19 <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="XiY-wd-750">
20 <rect key="frame" x="0.0" y="20" width="375" height="44"/>
20 <rect key="frame" x="0.0" y="20" width="375" height="44"/>
21 <autoresizingMask key="autoresizingMask"/>
21 <autoresizingMask key="autoresizingMask"/>
@@ -90,9 +90,6 @@
90 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yir-N6-Q6f">
90 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yir-N6-Q6f">
91 <rect key="frame" x="246" y="0.0" width="97" height="30"/>
91 <rect key="frame" x="246" y="0.0" width="97" height="30"/>
92 <state key="normal" title="New message"/>
92 <state key="normal" title="New message"/>
93− <connections>
94− <action selector="sendMessage:" destination="R4D-Ao-uvG" eventType="touchUpInside" id="tQc-5f-SU3"/>
95− </connections>
96 </button>
93 </button>
97 </subviews>
94 </subviews>
98 </stackView>
95 </stackView>
@@ -231,250 +228,6 @@
231 </objects>
228 </objects>
232 <point key="canvasLocation" x="2799" y="1979"/>
229 <point key="canvasLocation" x="2799" y="1979"/>
233 </scene>
230 </scene>
234− <!--Code View Controller-->
235− <scene sceneID="VW5-ny-vaB">
236− <objects>
237− <viewController storyboardIdentifier="CodeViewController" id="Lz1-1J-ywG" customClass="CodeViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
238− <view key="view" contentMode="scaleToFill" id="Rud-1x-pKL">
239− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
240− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
241− <subviews>
242− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enter the code you received via mail" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hE6-cQ-NbO">
243− <rect key="frame" x="50" y="47" width="275.5" height="20.5"/>
244− <fontDescription key="fontDescription" type="system" pointSize="17"/>
245− <nil key="textColor"/>
246− <nil key="highlightedColor"/>
247− </label>
248− <stackView opaque="NO" contentMode="scaleToFill" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="2Gj-pC-RZ2">
249− <rect key="frame" x="37.5" y="99" width="300" height="58"/>
250− <subviews>
251− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="744-t1-YNn">
252− <rect key="frame" x="0.0" y="0.0" width="40" height="58"/>
253− <nil key="textColor"/>
254− <fontDescription key="fontDescription" type="system" pointSize="45"/>
255− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
256− </textField>
257− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="jcR-jp-s7a">
258− <rect key="frame" x="52" y="0.0" width="40" height="58"/>
259− <nil key="textColor"/>
260− <fontDescription key="fontDescription" type="system" pointSize="45"/>
261− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
262− </textField>
263− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="YKO-0M-KD8">
264− <rect key="frame" x="104" y="0.0" width="40" height="58"/>
265− <nil key="textColor"/>
266− <fontDescription key="fontDescription" type="system" pointSize="45"/>
267− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
268− </textField>
269− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="SmG-Ae-oOs">
270− <rect key="frame" x="156" y="0.0" width="40" height="58"/>
271− <nil key="textColor"/>
272− <fontDescription key="fontDescription" type="system" pointSize="45"/>
273− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
274− </textField>
275− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="vaP-rO-NZW">
276− <rect key="frame" x="208" y="0.0" width="40" height="58"/>
277− <nil key="textColor"/>
278− <fontDescription key="fontDescription" type="system" pointSize="45"/>
279− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
280− </textField>
281− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="qDh-32-HSn">
282− <rect key="frame" x="260" y="0.0" width="40" height="58"/>
283− <nil key="textColor"/>
284− <fontDescription key="fontDescription" type="system" pointSize="45"/>
285− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
286− </textField>
287− </subviews>
288− <constraints>
289− <constraint firstAttribute="height" constant="58" id="5tl-bI-7tm"/>
290− <constraint firstItem="YKO-0M-KD8" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="E7r-rk-4Mb"/>
291− <constraint firstItem="SmG-Ae-oOs" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Hkd-L6-qkf"/>
292− <constraint firstItem="qDh-32-HSn" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Koj-e5-Dof"/>
293− <constraint firstItem="vaP-rO-NZW" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Vzl-ZY-3yI"/>
294− <constraint firstItem="jcR-jp-s7a" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="bDe-cA-CGi"/>
295− <constraint firstAttribute="width" constant="300" id="gWy-t0-k14"/>
296− </constraints>
297− </stackView>
298− <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lCU-OF-giE">
299− <rect key="frame" x="0.0" y="617" width="375" height="50"/>
300− <subviews>
301− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AMw-Yp-yMs">
302− <rect key="frame" x="327" y="8" width="32" height="30"/>
303− <state key="normal" title="Next"/>
304− <connections>
305− <action selector="whereToGoNext:" destination="Lz1-1J-ywG" eventType="touchUpInside" id="1OA-n8-Gky"/>
306− </connections>
307− </button>
308− </subviews>
309− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
310− <constraints>
311− <constraint firstAttribute="bottom" secondItem="AMw-Yp-yMs" secondAttribute="bottom" constant="12" id="7qy-qR-6jm"/>
312− <constraint firstItem="AMw-Yp-yMs" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="lCU-OF-giE" secondAttribute="leading" constant="20" symbolic="YES" id="Bqz-qr-CNW"/>
313− <constraint firstAttribute="height" constant="50" id="Dyu-H3-S3f"/>
314− <constraint firstAttribute="trailing" secondItem="AMw-Yp-yMs" secondAttribute="trailing" constant="16" id="N19-bz-XCw"/>
315− <constraint firstItem="AMw-Yp-yMs" firstAttribute="top" secondItem="lCU-OF-giE" secondAttribute="top" constant="8" id="u6d-3F-1Y5"/>
316− </constraints>
317− </view>
318− </subviews>
319− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
320− <constraints>
321− <constraint firstItem="hE6-cQ-NbO" firstAttribute="top" secondItem="xwd-51-foC" secondAttribute="top" constant="27" id="8Gx-SH-Pc0"/>
322− <constraint firstItem="2Gj-pC-RZ2" firstAttribute="top" secondItem="hE6-cQ-NbO" secondAttribute="bottom" constant="31.5" id="DEY-u8-rFj"/>
323− <constraint firstItem="lCU-OF-giE" firstAttribute="leading" secondItem="xwd-51-foC" secondAttribute="leading" id="HFt-0X-LMb"/>
324− <constraint firstItem="lCU-OF-giE" firstAttribute="trailing" secondItem="xwd-51-foC" secondAttribute="trailing" id="Z71-jX-S5Q"/>
325− <constraint firstItem="2Gj-pC-RZ2" firstAttribute="centerX" secondItem="xwd-51-foC" secondAttribute="centerX" id="aSr-QZ-LuB"/>
326− <constraint firstItem="hE6-cQ-NbO" firstAttribute="centerX" secondItem="xwd-51-foC" secondAttribute="centerX" id="oFz-CS-SSk"/>
327− <constraint firstItem="lCU-OF-giE" firstAttribute="bottom" secondItem="xwd-51-foC" secondAttribute="bottom" id="vMF-KP-eIa"/>
328− </constraints>
329− <viewLayoutGuide key="safeArea" id="xwd-51-foC"/>
330− </view>
331− <connections>
332− <outlet property="bottomConstraint" destination="vMF-KP-eIa" id="a15-El-XZs"/>
333− <outlet property="f1" destination="744-t1-YNn" id="kaQ-nt-ubz"/>
334− <outlet property="f2" destination="jcR-jp-s7a" id="tjD-L6-nis"/>
335− <outlet property="f3" destination="YKO-0M-KD8" id="QHg-UM-Bta"/>
336− <outlet property="f4" destination="SmG-Ae-oOs" id="bwy-JB-My7"/>
337− <outlet property="f5" destination="vaP-rO-NZW" id="rNh-iH-648"/>
338− <outlet property="f6" destination="qDh-32-HSn" id="h4g-QY-abI"/>
339− </connections>
340− </viewController>
341− <placeholder placeholderIdentifier="IBFirstResponder" id="y6E-3d-hPA" userLabel="First Responder" sceneMemberID="firstResponder"/>
342− </objects>
343− <point key="canvasLocation" x="4381.6000000000004" y="1961.4692653673164"/>
344− </scene>
345− <!--Register Table View Controller-->
346− <scene sceneID="h6T-rh-iCS">
347− <objects>
348− <tableViewController storyboardIdentifier="RegisterTableViewController" id="gZg-8R-SiJ" customClass="RegisterTableViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
349− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="yDm-gG-Zw0">
350− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
351− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
352− <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
353− <prototypes>
354− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="cell111" textLabel="bby-bf-qyX" style="IBUITableViewCellStyleDefault" id="Ybe-Vg-GR0">
355− <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
356− <autoresizingMask key="autoresizingMask"/>
357− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Ybe-Vg-GR0" id="OZG-F0-QqJ">
358− <rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
359− <autoresizingMask key="autoresizingMask"/>
360− <subviews>
361− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Add faculty" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="bby-bf-qyX">
362− <rect key="frame" x="16" y="0.0" width="324" height="43.5"/>
363− <autoresizingMask key="autoresizingMask"/>
364− <fontDescription key="fontDescription" type="system" pointSize="17"/>
365− <nil key="textColor"/>
366− <nil key="highlightedColor"/>
367− </label>
368− </subviews>
369− </tableViewCellContentView>
370− </tableViewCell>
371− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="facultyCell" textLabel="8Xf-Sx-eEe" detailTextLabel="Vjg-Il-F07" style="IBUITableViewCellStyleSubtitle" id="xJW-zY-MeC">
372− <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
373− <autoresizingMask key="autoresizingMask"/>
374− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xJW-zY-MeC" id="hnt-oe-CHh">
375− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
376− <autoresizingMask key="autoresizingMask"/>
377− <subviews>
378− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Add faculty" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8Xf-Sx-eEe">
379− <rect key="frame" x="16" y="5" width="87" height="20.5"/>
380− <autoresizingMask key="autoresizingMask"/>
381− <fontDescription key="fontDescription" type="system" pointSize="17"/>
382− <nil key="textColor"/>
383− <nil key="highlightedColor"/>
384− </label>
385− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Vjg-Il-F07">
386− <rect key="frame" x="16" y="25.5" width="44" height="14.5"/>
387− <autoresizingMask key="autoresizingMask"/>
388− <fontDescription key="fontDescription" type="system" pointSize="12"/>
389− <nil key="textColor"/>
390− <nil key="highlightedColor"/>
391− </label>
392− </subviews>
393− </tableViewCellContentView>
394− </tableViewCell>
395− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="nameCell" id="VPG-zq-xMh" customClass="InititalsViewCell" customModule="GDproject" customModuleProvider="target">
396− <rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
397− <autoresizingMask key="autoresizingMask"/>
398− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VPG-zq-xMh" id="jrO-rB-x0c">
399− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
400− <autoresizingMask key="autoresizingMask"/>
401− <subviews>
402− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hwQ-St-DAp">
403− <rect key="frame" x="16" y="7" width="343" height="30"/>
404− <constraints>
405− <constraint firstAttribute="height" constant="30" id="QXw-Sf-Hnk"/>
406− </constraints>
407− <nil key="textColor"/>
408− <fontDescription key="fontDescription" type="system" pointSize="17"/>
409− <textInputTraits key="textInputTraits"/>
410− </textField>
411− </subviews>
412− <constraints>
413− <constraint firstAttribute="bottom" secondItem="hwQ-St-DAp" secondAttribute="bottom" constant="6.5" id="3Kb-PR-ZPu"/>
414− <constraint firstItem="hwQ-St-DAp" firstAttribute="top" secondItem="jrO-rB-x0c" secondAttribute="top" constant="7" id="CyQ-kQ-mce"/>
415− <constraint firstAttribute="trailing" secondItem="hwQ-St-DAp" secondAttribute="trailing" constant="16" id="HKq-mF-8h9"/>
416− <constraint firstItem="hwQ-St-DAp" firstAttribute="leading" secondItem="jrO-rB-x0c" secondAttribute="leading" constant="16" id="NoW-FW-Q6L"/>
417− </constraints>
418− </tableViewCellContentView>
419− <connections>
420− <outlet property="initialsTextField" destination="hwQ-St-DAp" id="VU3-m6-FnI"/>
421− </connections>
422− </tableViewCell>
423− </prototypes>
424− <connections>
425− <outlet property="dataSource" destination="gZg-8R-SiJ" id="OVm-5H-nyP"/>
426− <outlet property="delegate" destination="gZg-8R-SiJ" id="khe-nG-0w4"/>
427− </connections>
428− </tableView>
429− </tableViewController>
430− <placeholder placeholderIdentifier="IBFirstResponder" id="0cS-ao-ZWH" userLabel="First Responder" sceneMemberID="firstResponder"/>
431− </objects>
432− <point key="canvasLocation" x="5925.6000000000004" y="2041.529235382309"/>
433− </scene>
434− <!--Faculty Table View Controller-->
435− <scene sceneID="WcK-wN-L0e">
436− <objects>
437− <tableViewController storyboardIdentifier="FacultyTableViewController" id="wiz-jF-9HF" customClass="FacultyTableViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
438− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="Iny-a7-zjv">
439− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
440− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
441− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
442− <prototypes>
443− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="F" textLabel="mSQ-7c-C8A" detailTextLabel="YuF-0p-znr" style="IBUITableViewCellStyleSubtitle" id="Otu-BR-9o9">
444− <rect key="frame" x="0.0" y="28" width="375" height="44"/>
445− <autoresizingMask key="autoresizingMask"/>
446− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Otu-BR-9o9" id="2Vm-f8-txH">
447− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
448− <autoresizingMask key="autoresizingMask"/>
449− <subviews>
450− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="mSQ-7c-C8A">
451− <rect key="frame" x="16" y="5" width="33.5" height="20.5"/>
452− <autoresizingMask key="autoresizingMask"/>
453− <fontDescription key="fontDescription" type="system" pointSize="17"/>
454− <nil key="textColor"/>
455− <nil key="highlightedColor"/>
456− </label>
457− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="YuF-0p-znr">
458− <rect key="frame" x="16" y="25.5" width="44" height="14.5"/>
459− <autoresizingMask key="autoresizingMask"/>
460− <fontDescription key="fontDescription" type="system" pointSize="12"/>
461− <nil key="textColor"/>
462− <nil key="highlightedColor"/>
463− </label>
464− </subviews>
465− </tableViewCellContentView>
466− </tableViewCell>
467− </prototypes>
468− <connections>
469− <outlet property="dataSource" destination="wiz-jF-9HF" id="db0-qR-UJy"/>
470− <outlet property="delegate" destination="wiz-jF-9HF" id="i3e-Uc-EfR"/>
471− </connections>
472− </tableView>
473− </tableViewController>
474− <placeholder placeholderIdentifier="IBFirstResponder" id="Kkr-Cr-ZiV" userLabel="First Responder" sceneMemberID="firstResponder"/>
475− </objects>
476− <point key="canvasLocation" x="6804" y="2044"/>
477− </scene>
478 <!--Simplified Channels List-->
231 <!--Simplified Channels List-->
479 <scene sceneID="gAa-jy-vpG">
232 <scene sceneID="gAa-jy-vpG">
480 <objects>
233 <objects>
@@ -626,35 +379,33 @@
626 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
379 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
627 <subviews>
380 <subviews>
628 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aRT-Du-PVE">
381 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aRT-Du-PVE">
629− <rect key="frame" x="0.0" y="62" width="375" height="605"/>
382+ <rect key="frame" x="0.0" y="55" width="375" height="612"/>
630 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
383 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
631 </view>
384 </view>
632− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bHv-9b-9uA">
385+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="368-bf-QU6">
633− <rect key="frame" x="16" y="32" width="343" height="30"/>
386+ <rect key="frame" x="0.0" y="20" width="375" height="35"/>
387+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
634 <constraints>
388 <constraints>
635− <constraint firstAttribute="height" constant="30" id="QPs-3f-AfA"/>
389+ <constraint firstAttribute="height" constant="35" id="5ER-su-0Yf"/>
636 </constraints>
390 </constraints>
637− <state key="normal" title="Edit hashtags"/>
391+ </view>
638− <connections>
639− <action selector="chooseTags:" destination="uED-wX-77j" eventType="touchUpInside" id="jvf-w2-K2f"/>
640− </connections>
641− </button>
642 </subviews>
392 </subviews>
643 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
393 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
644 <constraints>
394 <constraints>
645 <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="aRT-Du-PVE" secondAttribute="trailing" id="2ee-e8-G7A"/>
395 <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="aRT-Du-PVE" secondAttribute="trailing" id="2ee-e8-G7A"/>
646− <constraint firstItem="aRT-Du-PVE" firstAttribute="top" secondItem="bHv-9b-9uA" secondAttribute="bottom" id="6As-MU-bEh"/>
647− <constraint firstItem="bHv-9b-9uA" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" constant="16" id="OIV-hF-TBs"/>
396+ <constraint firstItem="368-bf-QU6" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="9Rl-wh-kZf"/>
648− <constraint firstItem="bHv-9b-9uA" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" constant="12" id="REt-Jv-IfH"/>
649 <constraint firstItem="aRT-Du-PVE" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="UBy-Ch-zSL"/>
397 <constraint firstItem="aRT-Du-PVE" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="UBy-Ch-zSL"/>
398+ <constraint firstItem="aRT-Du-PVE" firstAttribute="top" secondItem="368-bf-QU6" secondAttribute="bottom" id="WaE-kh-6w3"/>
399+ <constraint firstItem="368-bf-QU6" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" id="aI9-JQ-7dq"/>
650− <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="bHv-9b-9uA" secondAttribute="trailing" constant="16" id="Ufp-mQ-Xeo"/>
400+ <constraint firstItem="368-bf-QU6" firstAttribute="trailing" secondItem="wxD-Ek-mgv" secondAttribute="trailing" id="haz-0r-Cud"/>
651 <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="aRT-Du-PVE" secondAttribute="bottom" id="x3f-eb-ACt"/>
401 <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="aRT-Du-PVE" secondAttribute="bottom" id="x3f-eb-ACt"/>
652 </constraints>
402 </constraints>
653 <viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
403 <viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
654 </view>
404 </view>
655 <connections>
405 <connections>
656 <outlet property="bottomTextViewConstraint" destination="x3f-eb-ACt" id="ktT-im-InH"/>
406 <outlet property="bottomTextViewConstraint" destination="x3f-eb-ACt" id="ktT-im-InH"/>
657− <outlet property="view1" destination="aRT-Du-PVE" id="DXD-HR-NcE"/>
407+ <outlet property="view1" destination="aRT-Du-PVE" id="m3d-kW-vqW"/>
408+ <outlet property="viewForTags" destination="368-bf-QU6" id="M5s-RZ-Fq7"/>
658 </connections>
409 </connections>
659 </viewController>
410 </viewController>
660 <placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
411 <placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -679,96 +430,6 @@
679 </objects>
430 </objects>
680 <point key="canvasLocation" x="3444" y="129.98500749625188"/>
431 <point key="canvasLocation" x="3444" y="129.98500749625188"/>
681 </scene>
432 </scene>
682− <!--Taggs Selection View Controller-->
683− <scene sceneID="74G-Lc-cqT">
684− <objects>
685− <viewController storyboardIdentifier="TaggsSelectionViewController" id="rQl-ri-9O8" customClass="TaggsSelectionViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
686− <view key="view" contentMode="scaleToFill" id="k3T-8B-NVf">
687− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
688− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
689− <subviews>
690− <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yeR-J3-ysT">
691− <rect key="frame" x="16" y="131" width="343" height="142"/>
692− <constraints>
693− <constraint firstAttribute="height" constant="142" id="1By-sC-rMT"/>
694− </constraints>
695− </containerView>
696− <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lEu-rZ-H6U">
697− <rect key="frame" x="16" y="306" width="343" height="184"/>
698− <constraints>
699− <constraint firstAttribute="height" constant="184" id="F0W-3R-hCj"/>
700− </constraints>
701− </containerView>
702− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Add tags:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uXC-Rm-Hek">
703− <rect key="frame" x="16" y="28" width="73" height="21"/>
704− <constraints>
705− <constraint firstAttribute="height" constant="21" id="KZW-ld-K8d"/>
706− </constraints>
707− <fontDescription key="fontDescription" type="system" pointSize="17"/>
708− <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
709− <nil key="highlightedColor"/>
710− </label>
711− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Suggested tags:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hvS-Ix-A23">
712− <rect key="frame" x="16" y="106" width="126" height="21"/>
713− <constraints>
714− <constraint firstAttribute="height" constant="21" id="ZJb-Aw-bLx"/>
715− </constraints>
716− <fontDescription key="fontDescription" type="system" pointSize="17"/>
717− <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
718− <nil key="highlightedColor"/>
719− </label>
720− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Chosen tags:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lxp-KC-Iua">
721− <rect key="frame" x="16" y="281" width="101" height="21"/>
722− <constraints>
723− <constraint firstAttribute="height" constant="21" id="aT7-BK-i42"/>
724− </constraints>
725− <fontDescription key="fontDescription" type="system" pointSize="17"/>
726− <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
727− <nil key="highlightedColor"/>
728− </label>
729− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="BgX-NT-7NG" customClass="TKTextField" customModule="TaggerKit">
730− <rect key="frame" x="16" y="57" width="343" height="30"/>
731− <constraints>
732− <constraint firstAttribute="height" constant="30" id="dBr-rd-Cg8"/>
733− </constraints>
734− <nil key="textColor"/>
735− <fontDescription key="fontDescription" type="system" pointSize="14"/>
736− <textInputTraits key="textInputTraits"/>
737− </textField>
738− </subviews>
739− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
740− <constraints>
741− <constraint firstItem="hvS-Ix-A23" firstAttribute="top" secondItem="BgX-NT-7NG" secondAttribute="bottom" constant="19" id="17U-ae-Gxa"/>
742− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="yeR-J3-ysT" secondAttribute="trailing" constant="16" id="9gG-QD-LG4"/>
743− <constraint firstItem="lxp-KC-Iua" firstAttribute="top" secondItem="yeR-J3-ysT" secondAttribute="bottom" constant="8" id="C3R-dM-Fzj"/>
744− <constraint firstItem="uXC-Rm-Hek" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="E6w-kw-7Uo"/>
745− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="hvS-Ix-A23" secondAttribute="trailing" constant="233" id="GLM-Fj-UeZ"/>
746− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lxp-KC-Iua" secondAttribute="trailing" constant="258" id="Pbc-Ul-Bqf"/>
747− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="uXC-Rm-Hek" secondAttribute="trailing" constant="286" id="Uc1-pS-uKg"/>
748− <constraint firstItem="lEu-rZ-H6U" firstAttribute="top" secondItem="lxp-KC-Iua" secondAttribute="bottom" constant="4" id="aew-vr-F7L"/>
749− <constraint firstItem="uXC-Rm-Hek" firstAttribute="top" secondItem="Oc2-oW-bST" secondAttribute="top" constant="8" id="dGW-ps-wNH"/>
750− <constraint firstItem="lxp-KC-Iua" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="gmr-z4-RMQ"/>
751− <constraint firstItem="BgX-NT-7NG" firstAttribute="top" secondItem="uXC-Rm-Hek" secondAttribute="bottom" constant="8" id="jqp-Lv-waU"/>
752− <constraint firstItem="yeR-J3-ysT" firstAttribute="top" secondItem="hvS-Ix-A23" secondAttribute="bottom" constant="4" id="nZ3-oH-0AF"/>
753− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="BgX-NT-7NG" secondAttribute="trailing" constant="16" id="pPk-Ih-GDO"/>
754− <constraint firstItem="yeR-J3-ysT" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qBn-xg-Ioc"/>
755− <constraint firstItem="lEu-rZ-H6U" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qCJ-rc-qBq"/>
756− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lEu-rZ-H6U" secondAttribute="trailing" constant="16" id="vaR-Zr-5nI"/>
757− <constraint firstItem="hvS-Ix-A23" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="vcb-xj-bM8"/>
758− <constraint firstItem="BgX-NT-7NG" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="xOL-J4-JIV"/>
759− </constraints>
760− <viewLayoutGuide key="safeArea" id="Oc2-oW-bST"/>
761− </view>
762− <connections>
763− <outlet property="addTagsTextField" destination="BgX-NT-7NG" id="3vt-U9-NYI"/>
764− <outlet property="searchContainerView" destination="yeR-J3-ysT" id="SzT-fM-A6H"/>
765− <outlet property="testContainer" destination="lEu-rZ-H6U" id="DTe-9O-VAi"/>
766− </connections>
767− </viewController>
768− <placeholder placeholderIdentifier="IBFirstResponder" id="eoH-1e-A6A" userLabel="First Responder" sceneMemberID="firstResponder"/>
769− </objects>
770− <point key="canvasLocation" x="4293.6000000000004" y="132.68365817091455"/>
771− </scene>
772 <!--Messages View Controller-->
433 <!--Messages View Controller-->
773 <scene sceneID="WSW-fr-Vf8">
434 <scene sceneID="WSW-fr-Vf8">
774 <objects>
435 <objects>
@@ -778,53 +439,29 @@
778 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
439 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
779 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
440 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
780 <prototypes>
441 <prototypes>
781− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MessageViewCell" rowHeight="78" id="67C-fT-WEV" customClass="MessageViewCell" customModule="GDproject" customModuleProvider="target">
442+ <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MessagesCell" textLabel="9br-gb-mg8" detailTextLabel="Jxd-We-VyC" style="IBUITableViewCellStyleSubtitle" id="67C-fT-WEV">
782− <rect key="frame" x="0.0" y="28" width="375" height="78"/>
443+ <rect key="frame" x="0.0" y="28" width="375" height="44"/>
783 <autoresizingMask key="autoresizingMask"/>
444 <autoresizingMask key="autoresizingMask"/>
784 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="67C-fT-WEV" id="O3b-Xv-UNk">
445 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="67C-fT-WEV" id="O3b-Xv-UNk">
785− <rect key="frame" x="0.0" y="0.0" width="375" height="77.5"/>
446+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
786 <autoresizingMask key="autoresizingMask"/>
447 <autoresizingMask key="autoresizingMask"/>
787 <subviews>
448 <subviews>
788− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xAY-IF-RpX">
789− <rect key="frame" x="229" y="11" width="130" height="15"/>
790− <constraints>
791− <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="130" id="f99-ZF-f8h"/>
792− </constraints>
793− <fontDescription key="fontDescription" type="system" pointSize="12"/>
794− <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
795− <nil key="highlightedColor"/>
796− </label>
797− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FG3-gU-0r1">
449+ <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9br-gb-mg8">
798− <rect key="frame" x="16" y="11" width="46" height="22"/>
450+ <rect key="frame" x="16" y="5" width="33.5" height="20.5"/>
799− <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
451+ <autoresizingMask key="autoresizingMask"/>
452+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
800 <nil key="textColor"/>
453 <nil key="textColor"/>
801 <nil key="highlightedColor"/>
454 <nil key="highlightedColor"/>
802 </label>
455 </label>
803− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nTy-rK-XTr">
456+ <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Jxd-We-VyC">
804− <rect key="frame" x="16" y="49" width="343" height="18"/>
457+ <rect key="frame" x="16" y="25.5" width="33" height="14.5"/>
458+ <autoresizingMask key="autoresizingMask"/>
805− <fontDescription key="fontDescription" type="system" pointSize="15"/>
459+ <fontDescription key="fontDescription" type="system" pointSize="12"/>
806 <nil key="textColor"/>
460 <nil key="textColor"/>
807 <nil key="highlightedColor"/>
461 <nil key="highlightedColor"/>
808 </label>
462 </label>
809 </subviews>
463 </subviews>
810− <constraints>
811− <constraint firstItem="nTy-rK-XTr" firstAttribute="top" secondItem="xAY-IF-RpX" secondAttribute="bottom" constant="23" id="09Y-aK-nD9"/>
812− <constraint firstItem="FG3-gU-0r1" firstAttribute="top" secondItem="O3b-Xv-UNk" secondAttribute="topMargin" id="4Hp-d5-9An"/>
813− <constraint firstItem="xAY-IF-RpX" firstAttribute="top" secondItem="O3b-Xv-UNk" secondAttribute="topMargin" id="G4f-oJ-7ud"/>
814− <constraint firstItem="nTy-rK-XTr" firstAttribute="trailing" secondItem="O3b-Xv-UNk" secondAttribute="trailingMargin" id="MaE-VM-KhL"/>
815− <constraint firstItem="nTy-rK-XTr" firstAttribute="leading" secondItem="O3b-Xv-UNk" secondAttribute="leadingMargin" id="OIX-rY-Leo"/>
816− <constraint firstItem="nTy-rK-XTr" firstAttribute="top" secondItem="FG3-gU-0r1" secondAttribute="bottom" constant="16" id="Qdj-s3-t60"/>
817− <constraint firstItem="nTy-rK-XTr" firstAttribute="bottom" secondItem="O3b-Xv-UNk" secondAttribute="bottomMargin" id="Rv3-Mz-Aed"/>
818− <constraint firstItem="FG3-gU-0r1" firstAttribute="leading" secondItem="O3b-Xv-UNk" secondAttribute="leadingMargin" id="iN1-KG-dYn"/>
819− <constraint firstItem="xAY-IF-RpX" firstAttribute="trailing" secondItem="O3b-Xv-UNk" secondAttribute="trailingMargin" id="opV-4x-VCk"/>
820− <constraint firstItem="xAY-IF-RpX" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FG3-gU-0r1" secondAttribute="trailing" constant="4" id="x9r-sM-t4x"/>
821− </constraints>
822 </tableViewCellContentView>
464 </tableViewCellContentView>
823− <connections>
824− <outlet property="dateLabel" destination="xAY-IF-RpX" id="fcz-re-BXk"/>
825− <outlet property="dialogName" destination="FG3-gU-0r1" id="gd7-ND-wCi"/>
826− <outlet property="lastMessagePreview" destination="nTy-rK-XTr" id="Cmo-IJ-2r0"/>
827− </connections>
828 </tableViewCell>
465 </tableViewCell>
829 </prototypes>
466 </prototypes>
830 <connections>
467 <connections>
@@ -835,18 +472,18 @@
835 </tableViewController>
472 </tableViewController>
836 <placeholder placeholderIdentifier="IBFirstResponder" id="fu3-z4-EY7" userLabel="First Responder" sceneMemberID="firstResponder"/>
473 <placeholder placeholderIdentifier="IBFirstResponder" id="fu3-z4-EY7" userLabel="First Responder" sceneMemberID="firstResponder"/>
837 </objects>
474 </objects>
838− <point key="canvasLocation" x="2681" y="918"/>
475+ <point key="canvasLocation" x="2798" y="932"/>
839 </scene>
476 </scene>
840 <!--People To Write View Controller-->
477 <!--People To Write View Controller-->
841 <scene sceneID="6Td-bq-Ebf">
478 <scene sceneID="6Td-bq-Ebf">
842 <objects>
479 <objects>
843 <tableViewController storyboardIdentifier="PeopleToWriteViewController" id="rUc-Tv-hWE" customClass="PeopleToWriteViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
480 <tableViewController storyboardIdentifier="PeopleToWriteViewController" id="rUc-Tv-hWE" customClass="PeopleToWriteViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
844− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsSelectionDuringEditing="YES" allowsMultipleSelection="YES" allowsMultipleSelectionDuringEditing="YES" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="PDb-NB-Ey6">
481+ <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="PDb-NB-Ey6">
845 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
482 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
846 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
483 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
847 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
484 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
848 <prototypes>
485 <prototypes>
849− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="peopleToWriteCell" textLabel="e4H-yo-W57" style="IBUITableViewCellStyleDefault" id="5ue-Sf-Blf">
486+ <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="peopleToWriteCell" textLabel="e4H-yo-W57" detailTextLabel="QSb-Bd-4gu" style="IBUITableViewCellStyleValue1" id="5ue-Sf-Blf">
850 <rect key="frame" x="0.0" y="28" width="375" height="44"/>
487 <rect key="frame" x="0.0" y="28" width="375" height="44"/>
851 <autoresizingMask key="autoresizingMask"/>
488 <autoresizingMask key="autoresizingMask"/>
852 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5ue-Sf-Blf" id="8Dr-YE-x7M">
489 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5ue-Sf-Blf" id="8Dr-YE-x7M">
@@ -854,44 +491,14 @@
854 <autoresizingMask key="autoresizingMask"/>
491 <autoresizingMask key="autoresizingMask"/>
855 <subviews>
492 <subviews>
856 <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="e4H-yo-W57">
493 <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="e4H-yo-W57">
857− <rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
494+ <rect key="frame" x="16" y="12" width="33.5" height="20.5"/>
858 <autoresizingMask key="autoresizingMask"/>
495 <autoresizingMask key="autoresizingMask"/>
859 <fontDescription key="fontDescription" type="system" pointSize="17"/>
496 <fontDescription key="fontDescription" type="system" pointSize="17"/>
860 <nil key="textColor"/>
497 <nil key="textColor"/>
861 <nil key="highlightedColor"/>
498 <nil key="highlightedColor"/>
862 </label>
499 </label>
863− </subviews>
864− </tableViewCellContentView>
865− </tableViewCell>
866− </prototypes>
867− <connections>
868− <outlet property="dataSource" destination="rUc-Tv-hWE" id="cuc-oZ-Sna"/>
869− <outlet property="delegate" destination="rUc-Tv-hWE" id="hw6-6X-Rlx"/>
870− </connections>
871− </tableView>
872− </tableViewController>
873− <placeholder placeholderIdentifier="IBFirstResponder" id="Zp5-b5-nn2" userLabel="First Responder" sceneMemberID="firstResponder"/>
874− </objects>
875− <point key="canvasLocation" x="3614" y="938"/>
876− </scene>
877− <!--Chat Info View Controller-->
878− <scene sceneID="1br-Xg-fR9">
879− <objects>
880− <tableViewController storyboardIdentifier="ChatInfoViewController" id="Rfd-Hp-Qqv" customClass="ChatInfoViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
881− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="Rvg-ok-cnE">
882− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
883− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
884− <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
885− <prototypes>
886− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" textLabel="EdJ-of-2FG" style="IBUITableViewCellStyleDefault" id="hl5-Uc-R53">
887− <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
888− <autoresizingMask key="autoresizingMask"/>
889− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hl5-Uc-R53" id="Oy5-4e-dPI">
890− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
891− <autoresizingMask key="autoresizingMask"/>
892− <subviews>
893− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="EdJ-of-2FG">
500+ <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QSb-Bd-4gu">
894− <rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
501+ <rect key="frame" x="315" y="12" width="44" height="20.5"/>
895 <autoresizingMask key="autoresizingMask"/>
502 <autoresizingMask key="autoresizingMask"/>
896 <fontDescription key="fontDescription" type="system" pointSize="17"/>
503 <fontDescription key="fontDescription" type="system" pointSize="17"/>
897 <nil key="textColor"/>
504 <nil key="textColor"/>
@@ -901,53 +508,43 @@
901 </tableViewCellContentView>
508 </tableViewCellContentView>
902 </tableViewCell>
509 </tableViewCell>
903 </prototypes>
510 </prototypes>
904− <sections/>
905 <connections>
511 <connections>
906− <outlet property="dataSource" destination="Rfd-Hp-Qqv" id="ThC-G8-che"/>
512+ <outlet property="dataSource" destination="rUc-Tv-hWE" id="cuc-oZ-Sna"/>
907− <outlet property="delegate" destination="Rfd-Hp-Qqv" id="1WG-zg-Ahf"/>
513+ <outlet property="delegate" destination="rUc-Tv-hWE" id="hw6-6X-Rlx"/>
908 </connections>
514 </connections>
909 </tableView>
515 </tableView>
910 </tableViewController>
516 </tableViewController>
911− <placeholder placeholderIdentifier="IBFirstResponder" id="KPW-41-EQd" userLabel="First Responder" sceneMemberID="firstResponder"/>
517+ <placeholder placeholderIdentifier="IBFirstResponder" id="Zp5-b5-nn2" userLabel="First Responder" sceneMemberID="firstResponder"/>
912 </objects>
518 </objects>
913− <point key="canvasLocation" x="5057" y="938"/>
519+ <point key="canvasLocation" x="3614" y="938"/>
914 </scene>
520 </scene>
915− <!--Tags Suggestion Controller-->
521+ <!--Dialog View Controller-->
916− <scene sceneID="gfS-IA-vBj">
522+ <scene sceneID="9ac-1R-s4m">
917 <objects>
523 <objects>
918− <tableViewController storyboardIdentifier="TagsSuggestionController" id="shX-JH-apo" customClass="TagsSuggestionController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
524+ <tableViewController storyboardIdentifier="DialogViewController" id="AVr-rR-mka" customClass="DialogViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
919− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="jTj-mU-lli">
525+ <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="NlQ-jM-tQP">
920 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
526 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
921 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
527 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
922 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
528 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
923 <prototypes>
529 <prototypes>
924− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="cell" textLabel="Lbu-Z7-fTN" style="IBUITableViewCellStyleDefault" id="pnl-jg-9DL">
530+ <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="bgd-9d-SmR">
925 <rect key="frame" x="0.0" y="28" width="375" height="44"/>
531 <rect key="frame" x="0.0" y="28" width="375" height="44"/>
926 <autoresizingMask key="autoresizingMask"/>
532 <autoresizingMask key="autoresizingMask"/>
927− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pnl-jg-9DL" id="Vsm-Ic-k7e">
533+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="bgd-9d-SmR" id="9W4-bO-4MN">
928 <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
534 <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
929 <autoresizingMask key="autoresizingMask"/>
535 <autoresizingMask key="autoresizingMask"/>
930− <subviews>
931− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Lbu-Z7-fTN">
932− <rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
933− <autoresizingMask key="autoresizingMask"/>
934− <fontDescription key="fontDescription" type="system" pointSize="17"/>
935− <nil key="textColor"/>
936− <nil key="highlightedColor"/>
937− </label>
938− </subviews>
939 </tableViewCellContentView>
536 </tableViewCellContentView>
940 </tableViewCell>
537 </tableViewCell>
941 </prototypes>
538 </prototypes>
942 <connections>
539 <connections>
943− <outlet property="dataSource" destination="shX-JH-apo" id="a9b-xm-VIg"/>
540+ <outlet property="dataSource" destination="AVr-rR-mka" id="quz-3V-jDT"/>
944− <outlet property="delegate" destination="shX-JH-apo" id="Cg4-aC-E7h"/>
541+ <outlet property="delegate" destination="AVr-rR-mka" id="R4y-E9-LVr"/>
945 </connections>
542 </connections>
946 </tableView>
543 </tableView>
947 </tableViewController>
544 </tableViewController>
948− <placeholder placeholderIdentifier="IBFirstResponder" id="RsJ-xx-GJW" userLabel="First Responder" sceneMemberID="firstResponder"/>
545+ <placeholder placeholderIdentifier="IBFirstResponder" id="Tzh-O8-O7T" userLabel="First Responder" sceneMemberID="firstResponder"/>
949 </objects>
546 </objects>
950− <point key="canvasLocation" x="5925" y="1339"/>
547+ <point key="canvasLocation" x="4336" y="937"/>
951 </scene>
548 </scene>
952 <!--Channel View Controller-->
549 <!--Channel View Controller-->
953 <scene sceneID="myW-UY-uGB">
550 <scene sceneID="myW-UY-uGB">
@@ -996,7 +593,7 @@
996 </tableViewController>
593 </tableViewController>
997 <placeholder placeholderIdentifier="IBFirstResponder" id="W3K-lW-jpq" userLabel="First Responder" sceneMemberID="firstResponder"/>
594 <placeholder placeholderIdentifier="IBFirstResponder" id="W3K-lW-jpq" userLabel="First Responder" sceneMemberID="firstResponder"/>
998 </objects>
595 </objects>
999− <point key="canvasLocation" x="5844" y="448"/>
596+ <point key="canvasLocation" x="5531" y="656"/>
1000 </scene>
597 </scene>
1001 <!--Add To ChannelVC-->
598 <!--Add To ChannelVC-->
1002 <scene sceneID="Qir-mq-wma">
599 <scene sceneID="Qir-mq-wma">
@@ -1024,7 +621,7 @@
1024 </tableViewController>
621 </tableViewController>
1025 <placeholder placeholderIdentifier="IBFirstResponder" id="kT3-kK-tSX" userLabel="First Responder" sceneMemberID="firstResponder"/>
622 <placeholder placeholderIdentifier="IBFirstResponder" id="kT3-kK-tSX" userLabel="First Responder" sceneMemberID="firstResponder"/>
1026 </objects>
623 </objects>
1027− <point key="canvasLocation" x="6548" y="448"/>
624+ <point key="canvasLocation" x="6287" y="653"/>
1028 </scene>
625 </scene>
1029 <!--Posts-->
626 <!--Posts-->
1030 <scene sceneID="RSd-UJ-34B">
627 <scene sceneID="RSd-UJ-34B">
@@ -1112,6 +709,5 @@
1112 <resources>
709 <resources>
1113 <image name="1" width="30" height="30"/>
710 <image name="1" width="30" height="30"/>
1114 <image name="5" width="30" height="30"/>
711 <image name="5" width="30" height="30"/>
1115− <image name="chat" width="30" height="30"/>
1116 </resources>
712 </resources>
1117</document>
713</document>
GDproject/Constants.swift−8
@@ -59,13 +59,5 @@ let channelViewControllerId = "ChannelViewController"
59
59
60let addToChannelVCId = "AddToChannelVC"
60let addToChannelVCId = "AddToChannelVC"
61
61
62−let taggsSelectionViewController = "TaggsSelectionViewController"
63−
64−let dialogViewController = "DialogViewController"
65−
66−let tagsSuggestionController = "TagsSuggestionController"
67−
68−let chatInfoViewController = "ChatInfoViewController"
69−
70let blueSystemColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)
62let blueSystemColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)
71
63
GDproject/Controller/ News and channels/AddToChannelVC.swift+26−41
@@ -15,42 +15,35 @@ enum DataSourse{
15class AddToChannelVC: UITableViewController {
15class AddToChannelVC: UITableViewController {
16
16
17 var channel: Model.Channels?
17 var channel: Model.Channels?
18+ var dataSourse: DataSourse = .people
18 weak var update: UpdatableChannel?
19 weak var update: UpdatableChannel?
19
20
20 // data sources for people and hashtags
21 // data sources for people and hashtags
21 var dataSourcePeople: [Model.Users] = Model.Channels.fullPeople
22 var dataSourcePeople: [Model.Users] = Model.Channels.fullPeople
23+ var fullTags: [String] = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
24+
22
25
23 var reloadtable: Bool = false {
26 var reloadtable: Bool = false {
24 didSet{
27 didSet{
25 tableView.reloadData()
28 tableView.reloadData()
26 }
29 }
27 }
30 }
28−
29− var filteredDataSource = [Model.Users]()
30−
31− func filterContentForSearchText(_ searchText: String, scope: String = "All")
32− {
33− filteredDataSource = dataSourcePeople.filter { $0.fullName().lowercased().contains(searchText.lowercased()) }
34− tableView.reloadData()
35− }
36
31
37 let searchC = UISearchController(searchResultsController: nil)
32 let searchC = UISearchController(searchResultsController: nil)
38
33
39 override func viewDidLoad() {
34 override func viewDidLoad() {
40 super.viewDidLoad()
35 super.viewDidLoad()
41
36
42− navigationItem.title = "People"
43 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
37 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
44 self.navigationItem.searchController = searchC
38 self.navigationItem.searchController = searchC
45 navigationItem.largeTitleDisplayMode = .never
39 navigationItem.largeTitleDisplayMode = .never
46 self.navigationItem.hidesSearchBarWhenScrolling = false
40 self.navigationItem.hidesSearchBarWhenScrolling = false
47− definesPresentationContext = true
41+
48− searchC.searchResultsUpdater = self
49− searchC.obscuresBackgroundDuringPresentation = false
50 }
42 }
51
43
52 override func viewWillDisappear(_ animated: Bool) {
44 override func viewWillDisappear(_ animated: Bool) {
53 super.viewWillDisappear(animated)
45 super.viewWillDisappear(animated)
46+
54 update?.updateChannel(with: channel!)
47 update?.updateChannel(with: channel!)
55 }
48 }
56 // MARK: - Table view data source
49 // MARK: - Table view data source
@@ -59,19 +52,12 @@ class AddToChannelVC: UITableViewController {
59 return 1
52 return 1
60 }
53 }
61
54
62− var isFiltering: Bool {
63− return searchC.isActive && !searchBarIsEmpty()
64− }
65−
66− func searchBarIsEmpty() -> Bool {
67− return searchC.searchBar.text?.isEmpty ?? true
68− }
69−
70 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
55 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
71− if isFiltering {
56+ switch dataSourse {
72− return filteredDataSource.count
57+ case .people:
73− } else {
74 return dataSourcePeople.count
58 return dataSourcePeople.count
59+ default:
60+ return fullTags.count
75 }
61 }
76 }
62 }
77
63
@@ -79,16 +65,17 @@ class AddToChannelVC: UITableViewController {
79 {
65 {
80 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
66 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
81
67
82− if isFiltering{
68+ switch dataSourse {
69+ case .people:
83− cell.textLabel?.text = filteredDataSource[indexPath.row].fullName()
70+ cell.textLabel?.text = dataSourcePeople[indexPath.row].fullName()
84− if channel!.people.contains(filteredDataSource[indexPath.row].id) {
71+ if channel!.people.contains(dataSourcePeople[indexPath.row].id) {
85 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
72 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
86 } else {
73 } else {
87 cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
74 cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
88 }
75 }
89− } else {
76+ default:
90− cell.textLabel?.text = dataSourcePeople[indexPath.row].fullName()
77+ cell.textLabel?.text = "# \(fullTags[indexPath.row])"
91− if channel!.people.contains(dataSourcePeople[indexPath.row].id) {
78+ if channel!.tags.contains(fullTags[indexPath.row]) {
92 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
79 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
93 } else {
80 } else {
94 cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
81 cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
@@ -102,31 +89,29 @@ class AddToChannelVC: UITableViewController {
102
89
103 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
90 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
104 if let cell = tableView.cellForRow(at: indexPath) {
91 if let cell = tableView.cellForRow(at: indexPath) {
105− if isFiltering{
92+ switch dataSourse {
93+ case .people:
106 if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
94 if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
107− let filtered = channel!.people.filter{ $0 != filteredDataSource[indexPath.row].id }
95+ let filtered = channel!.people.filter{ $0 != dataSourcePeople[indexPath.row].id }
108 channel?.people = filtered
96 channel?.people = filtered
109 cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
97 cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
110 } else {
98 } else {
111− channel?.people.append(filteredDataSource[indexPath.row].id)
99+ channel?.people.append(dataSourcePeople[indexPath.row].id)
112 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
100 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
113 }
101 }
114− } else {
102+ default: //tags
115 if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
103 if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
116− let filtered = channel!.people.filter{ $0 != dataSourcePeople[indexPath.row].id }
104+ let filtered = channel!.tags.filter{
105+ !fullTags[indexPath.row].contains($0)
106+ }
117− channel?.people = filtered
107+ channel?.tags = filtered
118 cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
108 cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
119 } else {
109 } else {
120− channel?.people.append(dataSourcePeople[indexPath.row].id)
110+ channel?.tags.append(fullTags[indexPath.row])
121 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
111 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
122 }
112 }
123 }
113 }
124 }
114 }
125 }
115 }
126−}
127
116
128−extension AddToChannelVC : UISearchResultsUpdating {
129− func updateSearchResults(for searchController: UISearchController) {
130− filterContentForSearchText(searchController.searchBar.text!)
131− }
132}
117}
GDproject/Controller/ News and channels/AnonimousChannelController.swiftnew file+18
@@ -0,0 +1,18 @@
1+//
2+// AnonimousChannelController.swift
3+// GDproject
4+//
5+// Created by cstore on 20/04/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class AnonimousChannelController: UITableViewController {
12+
13+ override func viewDidLoad() {
14+ super.viewDidLoad()
15+ }
16+
17+
18+}
GDproject/Controller/ News and channels/ChannelController.swift+1−1
@@ -73,7 +73,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
73 if let _ = channel?.id { print("update")
73 if let _ = channel?.id { print("update")
74 Model.updateChannel(with: channel!)
74 Model.updateChannel(with: channel!)
75 } else { print("create")
75 } else { print("create")
76− //Model.createChannel(with: channel!)
76+ Model.createChannel(with: channel!)
77 }
77 }
78 return
78 return
79 }
79 }
GDproject/Controller/ News and channels/ChannelListController.swift+2−2
@@ -30,7 +30,7 @@ class ChannelListController: UITableViewController {
30 var displayingChannel: Model.Channels?
30 var displayingChannel: Model.Channels?
31
31
32 var toReload: Bool = false {
32 var toReload: Bool = false {
33− didSet {
33+ didSet{
34 tableView.reloadData()
34 tableView.reloadData()
35 }
35 }
36 }
36 }
@@ -100,7 +100,7 @@ class ChannelListController: UITableViewController {
100 @objc func addChannel()
100 @objc func addChannel()
101 {
101 {
102 // editing mode is on automatically
102 // editing mode is on automatically
103− onEditingModeBegins?(Model.Channels(people: [], name: "Untitled", id: 0, tags: []),IndexPath(row: 1, section: 0))
103+ onEditingModeBegins?(Model.Channels(people: [], name: "Untitled", tags: []),IndexPath(row: 1, section: 0))
104 }
104 }
105
105
106 static let generalChannel = Model.Channels(people: [], name: "General", id: -1, tags: [])
106 static let generalChannel = Model.Channels(people: [], name: "General", id: -1, tags: [])
GDproject/Controller/ News and channels/ChannelViewController.swift+17−30
@@ -16,15 +16,7 @@ protocol UpdatableChannel: class{
16 func updateChannel(with channel: Model.Channels)
16 func updateChannel(with channel: Model.Channels)
17}
17}
18
18
19−class ChannelViewController: UITableViewController, UpdatableName, UpdatableChannel, TagsReceiver
19+class ChannelViewController: UITableViewController, UpdatableName, UpdatableChannel {
20−{
21− var onChoosingHashTags: (([String]?)->())?
22−
23− var onChoosingPeople: ((Model.Channels?)->())?
24−
25− func receiveTags(tags: [String]) {
26− self.channel?.tags = tags
27− }
28
20
29 func updateName(with name: String){
21 func updateName(with name: String){
30 channel?.name = name
22 channel?.name = name
@@ -42,7 +34,7 @@ class ChannelViewController: UITableViewController, UpdatableName, UpdatableChan
42 override func viewDidLoad()
34 override func viewDidLoad()
43 {
35 {
44 super.viewDidLoad()
36 super.viewDidLoad()
45− tableView.keyboardDismissMode = .onDrag
37+
46 navigationItem.rightBarButtonItems = [ UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(showPreview)), self.editButtonItem]
38 navigationItem.rightBarButtonItems = [ UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(showPreview)), self.editButtonItem]
47 navigationItem.largeTitleDisplayMode = .never
39 navigationItem.largeTitleDisplayMode = .never
48 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
40 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
@@ -53,32 +45,26 @@ class ChannelViewController: UITableViewController, UpdatableName, UpdatableChan
53 super.viewWillAppear(animated)
45 super.viewWillAppear(animated)
54 tableView.reloadData()
46 tableView.reloadData()
55 }
47 }
56−
48+ // TODO: update channel
57 override func viewWillDisappear(_ animated: Bool) {
49 override func viewWillDisappear(_ animated: Bool) {
58
50
59 defer {
51 defer {
60 super.viewWillDisappear(animated)
52 super.viewWillDisappear(animated)
61 }
53 }
62
54
63− guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else
55+ guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else {
64− {
65− if let id = channel?.id, id != 0
56+ if let _ = channel?.id
66 {
57 {
67 Model.updateChannel(with: channel!)
58 Model.updateChannel(with: channel!)
68 } else {
59 } else {
69− Model.createChannel(with: channel!) {
60+ Model.createChannel(with: channel!)
70− [weak self] in
71− self?.showAlertOn(result: $0)
72− return
73− }
74 }
61 }
75 return
62 return
76 }
63 }
77 // nou
64 // nou
78 }
65 }
79
66
80− @objc func showPreview()
67+ @objc func showPreview(){
81− {
82 if let channel = channel {
68 if let channel = channel {
83 onShowingPreview?(channel)
69 onShowingPreview?(channel)
84 }
70 }
@@ -143,7 +129,7 @@ class ChannelViewController: UITableViewController, UpdatableName, UpdatableChan
143 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
129 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
144
130
145 if section == 1 {
131 if section == 1 {
146− cell.textLabel?.text = "👤 \(Model.Channels.fullPeopleDict[channel?.people[row-1] ?? 0]!.fullName())"
132+ cell.textLabel?.text = Model.Channels.fullPeopleDict[channel?.people[row-1] ?? 0]?.fullName()
147 } else {
133 } else {
148 cell.textLabel?.text = "# \(channel!.tags[row-1])"
134 cell.textLabel?.text = "# \(channel!.tags[row-1])"
149 }
135 }
@@ -153,8 +139,7 @@ class ChannelViewController: UITableViewController, UpdatableName, UpdatableChan
153
139
154 override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
140 override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
155 {
141 {
156− if editingStyle == UITableViewCell.EditingStyle.delete
142+ if editingStyle == UITableViewCell.EditingStyle.delete {
157− {
158 if indexPath.section == 1 {
143 if indexPath.section == 1 {
159 channel?.people.remove(at: indexPath.row-1)
144 channel?.people.remove(at: indexPath.row-1)
160 } else {
145 } else {
@@ -175,13 +160,15 @@ class ChannelViewController: UITableViewController, UpdatableName, UpdatableChan
175
160
176 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
161 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
177 {
162 {
178− if indexPath.row == 0 && indexPath.section == 1
163+ if indexPath.row == 0 && indexPath.section != 0
179 {
164 {
180− onChoosingPeople?(channel)
165+ let vc = storyboard?.instantiateViewController(withIdentifier: addToChannelVCId) as! AddToChannelVC
181− }
166+
182−
183− if indexPath.row == 0 && indexPath.section == 2 {
167+ vc.dataSourse = indexPath.section == 1 ? .people : .tags
184− onChoosingHashTags?(channel?.tags)
168+ vc.channel = channel
169+ vc.update = self
170+
171+ navigationController?.pushViewController(vc, animated: true)
185 }
172 }
186 }
173 }
187}
174}
GDproject/Controller/ News and channels/FullPostController.swift+19−3
@@ -25,10 +25,27 @@ class FullPostController: UITableViewController {
25
25
26 func setUpNavigationBar(){
26 func setUpNavigationBar(){
27 navigationItem.largeTitleDisplayMode = .never
27 navigationItem.largeTitleDisplayMode = .never
28− navigationItem.title = "Post"
28+ navigationItem.title = "\(post?.authorId ?? 0)"
29+ navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(self.options))]
29 }
30 }
30
31
31−
32+ @objc func options(){
33+ // drafts
34+ // saved
35+
36+ let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
37+ let editAction = UIAlertAction(title: "Send via message", style: .default)
38+ let shareAction = UIAlertAction(title: "Send via project", style: .default)
39+ let settingsAction = UIAlertAction(title: "Copy link", style: .default)
40+ let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
41+
42+ optionMenu.addAction(editAction)
43+ optionMenu.addAction(shareAction)
44+ optionMenu.addAction(settingsAction)
45+ optionMenu.addAction(cancelAction)
46+
47+ self.present(optionMenu, animated: true, completion: nil)
48+ }
32 // MARK: - Table view data source
49 // MARK: - Table view data source
33
50
34 override func numberOfSections(in tableView: UITableView) -> Int {
51 override func numberOfSections(in tableView: UITableView) -> Int {
@@ -85,7 +102,6 @@ class FullPostController: UITableViewController {
85 cell.onUserDisplay = { [weak self] (id) in
102 cell.onUserDisplay = { [weak self] (id) in
86 let vc = self?.storyboard!.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
103 let vc = self?.storyboard!.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
87 vc.idProfile = id
104 vc.idProfile = id
88−
89 self?.navigationController?.pushViewController(vc, animated: true)
105 self?.navigationController?.pushViewController(vc, animated: true)
90 }
106 }
91 default:
107 default:
GDproject/Controller/ News and channels/NewPostViewController.swift+10−46
@@ -10,38 +10,20 @@ import UIKit
10import Cartography
10import Cartography
11import Marklight
11import Marklight
12import TinyConstraints
12import TinyConstraints
13−import TaggerKit
14// import WSTagsField
13// import WSTagsField
15
14
16−class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
15+class NewPostViewController: UIViewController, UITextViewDelegate {
17−{
18− func receiveTags(tags: [String]) {
19− currentTags = tags
20− }
21
16
22 @IBOutlet weak var view1: UIView!
17 @IBOutlet weak var view1: UIView!
23
18
24− var currentTags: [String] = []
19+ @IBOutlet weak var viewForTags: UIView!
25−
26− // We want the whole experience, let's create two TKCollectionViews
27− let productTags = TKCollectionView()
28−
29− @IBAction func chooseTags(_ sender: UIButton) {
30− let vc = storyboard?.instantiateViewController(withIdentifier: taggsSelectionViewController) as! TaggsSelectionViewController
31−
32− NewPostViewController.draft = textView.text
33− vc.receiver = self
34− vc.currentTags = currentTags
35−
36− navigationController?.pushViewController(vc, animated: true)
37− }
38
20
39 // fileprivate let tagsField = WSTagsField()
21 // fileprivate let tagsField = WSTagsField()
40 // Keep strong instance of the `NSTextStorage` subclass
22 // Keep strong instance of the `NSTextStorage` subclass
41 let textStorage = MarklightTextStorage()
23 let textStorage = MarklightTextStorage()
42
24
43 static var draft: String = ""
25 static var draft: String = ""
44− static var hashTagsDraft: [String] = [ ]
26+ static var hashTagsDraft: [String] = []
45
27
46 var textView: UITextView!
28 var textView: UITextView!
47
29
@@ -72,7 +54,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
72
54
73 setUpMD()
55 setUpMD()
74 setUpTextView()
56 setUpTextView()
75− // setUpAccessoryView()
57+ setUpAccessoryView()
76 //setUpTagsView()
58 //setUpTagsView()
77 }
59 }
78
60
@@ -109,8 +91,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
109 override func viewWillAppear(_ animated: Bool) {
91 override func viewWillAppear(_ animated: Bool) {
110 super.viewWillAppear(animated)
92 super.viewWillAppear(animated)
111
93
112− //navigationController?.navigationBar.prefersLargeTitles = false
94+ navigationController?.navigationBar.prefersLargeTitles = false
113− navigationItem.largeTitleDisplayMode = .never
114 navigationItem.title = "New post"
95 navigationItem.title = "New post"
115 textView.text = NewPostViewController.draft
96 textView.text = NewPostViewController.draft
116 // tagsField.addTags(NewPostViewController.hashTagsDraft)
97 // tagsField.addTags(NewPostViewController.hashTagsDraft)
@@ -141,7 +122,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
141 func setUpTextView(){
122 func setUpTextView(){
142 view.addConstraint(bottomTextViewConstraint)
123 view.addConstraint(bottomTextViewConstraint)
143 view1.addSubview(textView)
124 view1.addSubview(textView)
144− textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(8) + .right(8))
125+ textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(40+8) + .right(8))
145
126
146 if #available(iOS 11.0, *) {
127 if #available(iOS 11.0, *) {
147 textView.smartDashesType = .no
128 textView.smartDashesType = .no
@@ -210,7 +191,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
210 }
191 }
211
192
212 func setUpMD(){
193 func setUpMD(){
213− textStorage.marklightTextProcessor.codeColor = UIColor.gray
194+ textStorage.marklightTextProcessor.codeColor = UIColor.orange
214 textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
195 textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
215 textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
196 textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
216 textStorage.marklightTextProcessor.codeFontName = "Courier"
197 textStorage.marklightTextProcessor.codeFontName = "Courier"
@@ -232,27 +213,10 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
232 var indexOfPost = 0
213 var indexOfPost = 0
233 // MARK:- new post
214 // MARK:- new post
234 @objc func newPost(){
215 @objc func newPost(){
235− self.navigationItem.title = "Sending..."
236− Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: currentTags) {
216+ Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: /*tagsField.tags.map { $0.text }*/ [])
237− [weak self] in
238−
239− switch $0 {
240− case .success1, .success:
241− NewPostViewController.draft = ""
242− NewPostViewController.hashTagsDraft = []
243− self?.moveBackToParentVC?()
244− default:
245− self?.showAlertOn(result: $0)
246− self?.navigationItem.title = "New post"
247− }
248−
249− }
250−
251− // NewPostViewController.draft = ""
252− // NewPostViewController.hashTagsDraft = []
253 // adding row to uiTableView after adding new post
217 // adding row to uiTableView after adding new post
254 // myProtocol?.addPost(post: p)
218 // myProtocol?.addPost(post: p)
255− // moveBackToParentVC?()
219+ moveBackToParentVC?()
256 // somewhere here i will be sending server notifications about new post arrival
220 // somewhere here i will be sending server notifications about new post arrival
257 }
221 }
258
222
@@ -264,7 +228,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
264 [weak self]
228 [weak self]
265 _ in
229 _ in
266 NewPostViewController.draft = self?.textView.text ?? ""
230 NewPostViewController.draft = self?.textView.text ?? ""
267− NewPostViewController.hashTagsDraft = self?.currentTags ?? []
231+ NewPostViewController.hashTagsDraft = /*self?.tagsField.tags.map { $0.text } ??*/ []
268 self?.moveBackToParentVC?()
232 self?.moveBackToParentVC?()
269 }
233 }
270
234
GDproject/Controller/ News and channels/NewsController.swift+14−53
@@ -12,7 +12,6 @@ import Cartography
12
12
13protocol UpdateableWithChannel: class {
13protocol UpdateableWithChannel: class {
14 var channel: Model.Channels? { get set }
14 var channel: Model.Channels? { get set }
15− func updateChannel(on channel: Model.Channels)
16}
15}
17
16
18protocol UpdateableWithUser: class {
17protocol UpdateableWithUser: class {
@@ -20,14 +19,8 @@ protocol UpdateableWithUser: class {
20}
19}
21// MARK:- Controller with posts and channels availiable.
20// MARK:- Controller with posts and channels availiable.
22// Search is availiable within every table (posts and channels). Has button-functionality for boths post and chnnels
21// Search is availiable within every table (posts and channels). Has button-functionality for boths post and chnnels
23−class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWithChannel, UISearchResultsUpdating
22+class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWithChannel
24{
23{
25− func updateChannel(on channel: Model.Channels) {
26− self.channel = channel
27− news.currChannel = channel
28− decideWhatChannelDisplay()
29− }
30−
31 var changedChannelName: ((String)->())?
24 var changedChannelName: ((String)->())?
32
25
33 @IBOutlet weak var tableView: UITableView!
26 @IBOutlet weak var tableView: UITableView!
@@ -38,7 +31,7 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
38 // MARK: - Output -
31 // MARK: - Output -
39 var onSelectChannel: (() -> Void)?
32 var onSelectChannel: (() -> Void)?
40
33
41− var searchController: UISearchController?
34+ var searchController = UISearchController(searchResultsController: nil)
42
35
43 var news = NewsVC()
36 var news = NewsVC()
44 var type: HeaderType? = .NEWS
37 var type: HeaderType? = .NEWS
@@ -48,13 +41,6 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
48 override func viewDidLoad()
41 override func viewDidLoad()
49 {
42 {
50 super.viewDidLoad()
43 super.viewDidLoad()
51−
52− let updater = TagsSuggestionController()
53− updater.delegate = self
54− searchController = UISearchController(searchResultsController: updater)
55− navigationItem.largeTitleDisplayMode = .always
56−
57− navigationController?.navigationBar.prefersLargeTitles = true
58 navigationItem.title = "Loading ..."
44 navigationItem.title = "Loading ..."
59 tableView.refreshControl = refreshContr
45 tableView.refreshControl = refreshContr
60 // Configure Refresh Control
46 // Configure Refresh Control
@@ -63,9 +49,8 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
63 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
49 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
64 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
50 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
65
51
66− setUpSearchContr()
52+ // setUpSearchContr()
67
53
68− // navigationItem.
69 news.viewController = self
54 news.viewController = self
70 news.type = type == .NEWS ? .NEWS : type!
55 news.type = type == .NEWS ? .NEWS : type!
71 news.currChannel = channel
56 news.currChannel = channel
@@ -74,15 +59,14 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
74 }
59 }
75
60
76 func setUpSearchContr(){
61 func setUpSearchContr(){
77− searchController?.delegate = self
62+ searchController.delegate = self
78− searchController?.obscuresBackgroundDuringPresentation = false
63+ searchController.obscuresBackgroundDuringPresentation = false
79 navigationItem.searchController = searchController
64 navigationItem.searchController = searchController
80 definesPresentationContext = true
65 definesPresentationContext = true
81− searchController?.searchResultsUpdater = self
82− searchController?.searchBar.placeholder = "Search tags"
66+ searchController.searchBar.placeholder = "Search anything"
83 }
67 }
84
68
85− @objc func refreshPostsData( _ ff: UIRefreshControl) {
69+ @objc func refreshPostsData( _ ff: UIRefreshControl){
86 decideWhatChannelDisplay()
70 decideWhatChannelDisplay()
87 }
71 }
88
72
@@ -92,7 +76,7 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
92
76
93 override func viewWillAppear(_ animated: Bool) {
77 override func viewWillAppear(_ animated: Bool) {
94 super.viewWillAppear(animated)
78 super.viewWillAppear(animated)
95− searchController?.isActive = false
79+ searchController.isActive = false
96 // TODO:- display something if no posts are availiable
80 // TODO:- display something if no posts are availiable
97
81
98 decideWhatChannelDisplay()
82 decideWhatChannelDisplay()
@@ -101,18 +85,16 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
101 }
85 }
102
86
103 func decideWhatChannelDisplay(){
87 func decideWhatChannelDisplay(){
104−
105 switch type! {
88 switch type! {
106 case .NEWS, .NONE:
89 case .NEWS, .NONE:
107 if let channel = channel, let id = channel.id, id != -1 {
90 if let channel = channel, let id = channel.id, id != -1 {
108
91
109− Model.getAnonymousChannel(by: channel) { [weak self] in
92+ Model.getChannel(with: id) { [weak self] in
110 self?.news.dataSourse = $0.posts
93 self?.news.dataSourse = $0.posts
111 self?.news.dictionary = $0.users
94 self?.news.dictionary = $0.users
112 self?.refreshContr.endRefreshing()
95 self?.refreshContr.endRefreshing()
113 self?.changedChannelName?(channel.name)
96 self?.changedChannelName?(channel.name)
114 }
97 }
115−
116 } else {
98 } else {
117 Model.getLast { [weak self] in
99 Model.getLast { [weak self] in
118 self?.news.dataSourse = $0.posts
100 self?.news.dataSourse = $0.posts
@@ -122,10 +104,12 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
122 }
104 }
123 }
105 }
124 default:
106 default:
125− refreshContr.endRefreshing()
107+ if let anonChannel = anonymousChannel {
126− break
108+ news.dataSourse = anonChannel.posts
109+ news.dictionary = anonChannel.users
110+ changedChannelName?("Anonymous")
111+ }
127 }
112 }
128−
129 }
113 }
130
114
131 func setUpNavigationItemsforPosts(){
115 func setUpNavigationItemsforPosts(){
@@ -133,27 +117,4 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
133 tableView.dataSource = news
117 tableView.dataSource = news
134 tableView.reloadData()
118 tableView.reloadData()
135 }
119 }
136−
137− func updateSearchResults(for searchController: UISearchController)
138− {
139− let filteredData = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: searchController.searchBar.text?.lowercased() ?? "")
140−
141− // Apply the filtered results to the search results table.
142− if let resultsController = searchController.searchResultsController as? TagsSuggestionController {
143− resultsController.suggestions = filteredData
144− resultsController.tableView.reloadData()
145− }
146− }
147−
148− func willPresentSearchController(_ searchController: UISearchController) {
149− searchController.searchResultsController?.view.isHidden = false;
150− }
151−
152− func didPresentSearchController(_ searchController: UISearchController) {
153− searchController.searchResultsController?.view.isHidden = false;
154− }
155−
156− func didDismissSearchController(_ searchController: UISearchController) {
157− searchController.searchBar.text = ""
158− }
159}
120}
GDproject/Controller/ News and channels/NewsVC.swift+11−12
@@ -19,9 +19,7 @@ struct PostCellData{
19
19
20 let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
20 let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
21 markdownParser.enabledElements = .disabledAutomaticLink
21 markdownParser.enabledElements = .disabledAutomaticLink
22− markdownParser.code.font = UIFont(name: "Menlo", size: 16)
23− markdownParser.code.textBackgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
22+ markdownParser.code.textBackgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
24− markdownParser.code.color = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
25
23
26 return markdownParser.parse(markdown)
24 return markdownParser.parse(markdown)
27 }
25 }
@@ -44,7 +42,6 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
44 }
42 }
45
43
46 (viewController as? NewsController)?.tableView.reloadData()
44 (viewController as? NewsController)?.tableView.reloadData()
47− (viewController as? ProfileViewController)?.tableView.reloadData()
48 }
45 }
49 }
46 }
50
47
@@ -88,17 +85,19 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
88 vc.idProfile = id
85 vc.idProfile = id
89 self?.viewController!.navigationController!.pushViewController(vc, animated: true)
86 self?.viewController!.navigationController!.pushViewController(vc, animated: true)
90 }
87 }
91−
92− cell.onAnonymousChannelDisplay = {
93− [weak self] in
94− (self?.viewController as? UpdateableWithChannel)?.updateChannel(on: Model.Channels(people: [], name: $0, id: 0, tags: [$0]))
95− }
96 default:
88 default:
97 cell.onUserDisplay = { (id) in
89 cell.onUserDisplay = { (id) in
98 print("tapped when profile is opened already \(id)")
90 print("tapped when profile is opened already \(id)")
99 }
91 }
100 }
92 }
101
93
94+ cell.onAnonymousChannelDisplay = {
95+ [weak self] (tag) in
96+ Model.getAnonymousChannel(by: Model.AnonymousChannel(people: [], tags: [tag]),
97+ completion: { (tuple) in self?.onChannelDidChange?(tuple) }
98+ )
99+ }
100+
102 cell.selectionStyle = .none
101 cell.selectionStyle = .none
103 return cell
102 return cell
104 }
103 }
@@ -118,13 +117,13 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
118 // pagination
117 // pagination
119 if indexPath.row == cellDataSourse.count - 1 && prevLast != indexPath.row
118 if indexPath.row == cellDataSourse.count - 1 && prevLast != indexPath.row
120 {
119 {
121− if let ch = currChannel, let id = ch.id, id != -1 {
120+ if let ch = currChannel, let id = ch.id, ch.id != -1{
122 // check this!
121 // check this!
123− Model.getAnonymousChannel(by: ch, exclusiveFrom: dataSourse.last?.id) { [weak self] in
122+ Model.getChannel(with: id, on: 10, from: dataSourse.last?.id )
123+ { [weak self] in
124 self?.dataSourse.append(contentsOf: $0.posts)
124 self?.dataSourse.append(contentsOf: $0.posts)
125 $0.users.forEach { self?.dictionary[$0.key] = $0.value }
125 $0.users.forEach { self?.dictionary[$0.key] = $0.value }
126 }
126 }
127−
128 } else {
127 } else {
129 // check this!
128 // check this!
130 Model.getLast(on: 10, from: dataSourse.last?.id )
129 Model.getLast(on: 10, from: dataSourse.last?.id )
GDproject/Controller/ News and channels/PostViewCell.swift+3−7
@@ -8,11 +8,11 @@
8
8
9import UIKit
9import UIKit
10import Cartography
10import Cartography
11+import MarkdownKit
11import TinyConstraints
12import TinyConstraints
12
13
13class PostViewCell: UITableViewCell
14class PostViewCell: UITableViewCell
14{
15{
15−
16 var onUserDisplay: ((Int)->())?
16 var onUserDisplay: ((Int)->())?
17
17
18 var onAnonymousChannelDisplay: ((String)->())?
18 var onAnonymousChannelDisplay: ((String)->())?
@@ -42,7 +42,6 @@ class PostViewCell: UITableViewCell
42
42
43 let shareButton: UIButton = {
43 let shareButton: UIButton = {
44 let button = UIButton(type: UIButton.ButtonType.detailDisclosure)
44 let button = UIButton(type: UIButton.ButtonType.detailDisclosure)
45− button.isHidden = true
46 return button
45 return button
47 }()
46 }()
48
47
@@ -87,7 +86,7 @@ class PostViewCell: UITableViewCell
87 nameLabel.setTitle("\(post.user?.firstName ?? "") \(post.user?.lastName ?? "")", for: .normal)
86 nameLabel.setTitle("\(post.user?.firstName ?? "") \(post.user?.lastName ?? "")", for: .normal)
88 nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
87 nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
89 if let user = post.user{
88 if let user = post.user{
90− fullNameLabel.text = "\(user.faculty.name)"
89+ fullNameLabel.text = "\(user.firstName) \(user.middleName) \(user.lastName)"
91 }
90 }
92 else {
91 else {
93 fullNameLabel.text = "\(post.authorId)"
92 fullNameLabel.text = "\(post.authorId)"
@@ -124,7 +123,6 @@ class PostViewCell: UITableViewCell
124 let button = UIButton()
123 let button = UIButton()
125 button.setTitle("#" + hash, for: .normal)
124 button.setTitle("#" + hash, for: .normal)
126 button.addTarget(self, action: #selector(setAnonymousChannel(on:)), for: .touchUpInside)
125 button.addTarget(self, action: #selector(setAnonymousChannel(on:)), for: .touchUpInside)
127− // button.addGestureRecognizer(longPressRecognizer)
128 button.titleLabel?.font = UIFont.monospacedDigitSystemFont(ofSize: 15, weight: .semibold)
126 button.titleLabel?.font = UIFont.monospacedDigitSystemFont(ofSize: 15, weight: .semibold)
129 button.setTitleColor(#colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1), for: .normal)
127 button.setTitleColor(#colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1), for: .normal)
130 buttons.append(button)
128 buttons.append(button)
@@ -182,9 +180,7 @@ class PostViewCell: UITableViewCell
182 }
180 }
183
181
184 @objc func displayProfile(){
182 @objc func displayProfile(){
185− if let id = post?.authorId {
183+ onUserDisplay?(post!.authorId)
186− onUserDisplay?(id)
187− }
188 }
184 }
189
185
190 @objc func setAnonymousChannel(on button: UIButton){
186 @objc func setAnonymousChannel(on button: UIButton){
GDproject/Controller/ News and channels/TaggsSelectionViewController.swiftdeleted−106
@@ -1,106 +0,0 @@
1−//
2−// TaggsSelectionViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 03/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TaggerKit
11−
12−protocol TagsReceiver: class {
13− func receiveTags(tags: [String])
14−}
15−
16−class TaggsSelectionViewController: UIViewController {
17−
18− @IBOutlet weak var addTagsTextField: TKTextField!
19−
20− @IBOutlet weak var searchContainerView: UIView!
21−
22− @IBOutlet weak var testContainer: UIView!
23−
24− // We want the whole experience, let's create two TKCollectionViews
25− let productTags = TKCollectionView()
26− let allTags = TKCollectionView()
27−
28− var currentTags: [String]?
29− weak var receiver: TagsReceiver?
30−
31− // MARK: - Lifecycle Methods
32− override func viewDidLoad() {
33− super.viewDidLoad()
34−
35− navigationItem.title = "Hashtags"
36− addTagsTextField.delegate = self
37− // Customisation example
38− // testCollection.customFont = UIFont.boldSystemFont(ofSize: 14) // Custom font
39− // testCollection.customCornerRadius = 14.0 // Corner radius of tags
40− // testCollection.customSpacing = 20.0 // Spacing between cells
41− // testCollection.customBackgroundColor = UIColor.red // Background of cells
42−
43−
44− // These are the tags already added by the user, give an aray of strings to the collection
45− if let tags = currentTags {
46− productTags.tags = tags
47− }
48− // These are intended to be all the tags the user has added in the app, which are going to be filtered
49− allTags.tags = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
50−
51− /*
52− We set this collection's action to .removeTag,
53− becasue these are supposed to be the tags the user has already added
54− */
55− productTags.action = .removeTag
56−
57−
58− // Set the current controller as the delegate of both collections
59− productTags.delegate = self
60− allTags.delegate = self
61−
62− // "testCollection" takes the tags sent by "searchCollection"
63− allTags.receiver = productTags
64−
65− // The tags in "searchCollection" are going to be added, so we set the action to addTag
66− allTags.action = .addTag
67−
68−
69− // Set the sender and receiver of the TextField
70− addTagsTextField.sender = allTags
71− addTagsTextField.receiver = productTags
72−
73− add(productTags, toView: testContainer)
74− add(allTags, toView: searchContainerView)
75− }
76−
77− override func viewWillDisappear(_ animated: Bool) {
78− super.viewWillDisappear(animated)
79− if let receiver = receiver{
80− receiver.receiveTags(tags: productTags.tags)
81− }
82− }
83−
84− /*
85− These methods come from UIViewController now conforming to TKCollectionViewDelegate,
86− You use these to do whatever you want when a tag is added or removed (e.g. save to file, etc)
87− */
88− override func tagIsBeingAdded(name: String?) {
89− // Example: save testCollection.tags to UserDefault
90− print("added \(name!)")
91− }
92−
93− override func tagIsBeingRemoved(name: String?) {
94− print("removed \(name!)")
95− }
96−}
97−
98−// textField deletage to close keyboard on return
99−extension TaggsSelectionViewController: UITextFieldDelegate
100−{
101− func textFieldShouldReturn(_ textField: UITextField) -> Bool
102− {
103− self.view.endEditing(true)
104− return false
105− }
106−}
GDproject/Controller/ News and channels/TagsSuggestionController.swiftdeleted−52
@@ -1,52 +0,0 @@
1−//
2−// AnonimousChannelController.swift
3−// GDproject
4−//
5−// Created by cstore on 20/04/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class TagsSuggestionController: UITableViewController
12−{
13− weak var delegate: UpdateableWithChannel?
14−
15− var suggestions = [String]()
16− var channel: Model.Channels?
17−
18− override func viewDidLoad()
19− {
20− super.viewDidLoad()
21− if let tree = Model.hashTagTree {
22− suggestions = CompletionTree.getCompletion(tree: tree, word: "")
23− print(suggestions)
24− }
25− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
26− tableView.reloadData()
27− }
28−
29− override func numberOfSections(in tableView: UITableView) -> Int {
30− return 1
31− }
32−
33− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
34− return suggestions.count
35− }
36−
37− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
38− {
39− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
40− cell.textLabel?.text = suggestions[indexPath.row]
41−
42− return cell
43− }
44−
45− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
46− {
47− channel = Model.Channels(people: [], name: "\(self.suggestions[indexPath.row])", id: 0, tags: [self.suggestions[indexPath.row]])
48−
49− delegate?.updateChannel(on: channel!)
50− self.dismiss(animated: true)
51− }
52−}
GDproject/Controller/Coordinators/ChannelsCoordinator.swift−20
@@ -55,26 +55,6 @@ class ChannelsCoordinator: BaseCoordinator{
55 let vc = self.presentNewsController(with: ch, previewMode: true)
55 let vc = self.presentNewsController(with: ch, previewMode: true)
56 mainContentVC?.navigationController?.pushViewController(vc, animated: true)
56 mainContentVC?.navigationController?.pushViewController(vc, animated: true)
57 }
57 }
58−
59− // to go for choosing hashtags
60− mainContentVC.onChoosingHashTags = { [weak mainContentVC, unowned self] ch in
61− let vc = self.storyboard.instantiateViewController(withIdentifier: taggsSelectionViewController) as! TaggsSelectionViewController
62−
63− vc.currentTags = ch
64− vc.receiver = mainContentVC
65−
66− self.navigationController?.pushViewController(vc, animated: true)
67− }
68−
69− mainContentVC.onChoosingPeople = { [weak mainContentVC, unowned self] channel in
70− let vc = self.storyboard.instantiateViewController(withIdentifier: addToChannelVCId) as! AddToChannelVC
71−
72− vc.channel = channel
73− vc.update = mainContentVC
74−
75− self.navigationController?.pushViewController(vc, animated: true)
76− }
77−
78 mainContentVC.channel = channel
58 mainContentVC.channel = channel
79 return mainContentVC
59 return mainContentVC
80 }
60 }
GDproject/Controller/Coordinators/LogInCoordinator.swift+8−37
@@ -10,8 +10,6 @@ import UIKit
10
10
11class LogInCoordinator: BaseCoordinator {
11class LogInCoordinator: BaseCoordinator {
12
12
13− let storyboard = UIStoryboard(name: "Main", bundle: nil)
14−
15 var didEndFlow: (()->())?
13 var didEndFlow: (()->())?
16 var window: UIWindow!
14 var window: UIWindow!
17 var navigationController: UINavigationController?
15 var navigationController: UINavigationController?
@@ -24,47 +22,20 @@ class LogInCoordinator: BaseCoordinator {
24
22
25 override func start(){
23 override func start(){
26 let logInVC = LogInViewController()
24 let logInVC = LogInViewController()
27− logInVC.authenticate = { [weak self, weak logInVC] (email) in
25+ logInVC.authenticate = { [weak self] (id) in
28
26
29− DataStorage.standard.setEmail(email: email)
30− Model.authenticate(with: email) { [weak self]
27+ Model.authenticate(with: id) {
31− (authStatus) in
28+ (res) in
32−
33− print(authStatus.userStatus)
34
29
35− if (authStatus.userStatus == "invalid") {
30+ if (res) {
36− logInVC?.presentAlertInvalidCode()
31+ DataStorage.standard.setUserKey(with: id)
32+ self?.didEndFlow?()
37 }
33 }
38− else if (authStatus.userStatus == "canRegister") { // register form
34+ else {
39− self?.presentRegisterVC()
35+ DataStorage.standard.setUserKey(with: 0)
40− } else { // validation code
41− self?.presentViewControllerForCodeInput()
42 }
36 }
43 }
37 }
44 }
38 }
45−
46 navigationController?.pushViewController(logInVC, animated: false)
39 navigationController?.pushViewController(logInVC, animated: false)
47 }
40 }
48−
49− func presentViewControllerForCodeInput()
50− {
51− let vc = storyboard.instantiateViewController(withIdentifier: "CodeViewController") as! CodeViewController
52− self.navigationController?.pushViewController(vc, animated: true)
53− vc.onSuccessLogIn = {
54− [weak self] in self?.didEndFlow?()
55− }
56− }
57−
58− func presentRegisterVC(){
59−
60− let vc1 = storyboard.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
61−
62− vc1.onRegistration = { [weak self] in
63− self?.presentViewControllerForCodeInput()
64− }
65−
66− self.navigationController?.pushViewController(vc1, animated: true)
67− }
68−
69−
70}
41}
GDproject/Controller/Coordinators/MessagesCoordinator.swift+3−45
@@ -32,56 +32,14 @@ class MessagesCoordinator: BaseCoordinator {
32 vc.onUserDisplayList = { [weak vc, unowned self] in
32 vc.onUserDisplayList = { [weak vc, unowned self] in
33
33
34 let newVC = self.storyboard.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
34 let newVC = self.storyboard.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
35−
36− newVC.whatToDoWithSelection = { [weak newVC, weak self] people in
37− newVC?.navigationController?.popViewController(animated: true)
38−
39− // detect is it a user or group dialog
40− let count = people.count
41− if count == 1 {
42−
43− let user = people.first!.key
44− let createdDialog = Model.Dialog.userChat(Model.UserChat(user: user))
45−
46− let vc = DialogViewController()
47− vc.users = Model.Channels.fullPeopleDict
48− vc.dialog = createdDialog
49− self?.navigationController?.pushViewController(vc, animated: true)
50−
51− } else {
52− var group = Model.Group(users: people, name: "Untitled", id: 0)
53− group.users[DataStorage.standard.getUserId()] = Model.UserPermission(isAdmin: true)
54−
55− Model.createGroupChat(from: group, completion: { [weak self] id in
56−
57− let newVC1 = DialogViewController()
58− group.id = id
59− newVC1.users = Model.Channels.fullPeopleDict
60− newVC1.dialog = Model.Dialog.groupChat(Model.GroupChat(group: group))
61− self?.navigationController?.pushViewController(newVC1, animated: true)
62− })
63− }
64− }
65−
66 vc?.navigationController?.pushViewController(newVC, animated: true)
35 vc?.navigationController?.pushViewController(newVC, animated: true)
67 }
36 }
68
37
69− vc.onDialogDisplay = { [weak vc] in
38+ vc.onDialogDisplay = { [weak vc, unowned self] in
70−
71− let newVC = DialogViewController()
72− newVC.dialog = $0.dialog
73− newVC.users = $0.users
74− newVC.onUserDisplay = { [weak self] id in
75−
76− let vc = self?.storyboard.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
39+ let newVC = self.storyboard.instantiateViewController(withIdentifier: dialogVC) as! DialogViewController
77− vc.idProfile = id
40+ newVC.currentDialog = $0
78− self?.navigationController!.pushViewController(vc, animated: true)
79−
80− }
81−
82 vc?.navigationController?.pushViewController(newVC, animated: true)
41 vc?.navigationController?.pushViewController(newVC, animated: true)
83 }
42 }
84−
85 navigationController?.viewControllers = [vc]
43 navigationController?.viewControllers = [vc]
86 }
44 }
87}
45}
GDproject/Controller/Coordinators/ProfileCoordinator.swift+16−22
@@ -27,34 +27,28 @@ class ProfileCoordinator: BaseCoordinator {
27 let storyboard = UIStoryboard(name: "Main", bundle: nil)
27 let storyboard = UIStoryboard(name: "Main", bundle: nil)
28 let profile = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
28 let profile = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
29
29
30− profile.logOut = {
30+ profile.logOut = { [weak self] in
31− Model.logout() {
32− [weak self] in
33−
34− DataStorage.standard.setIsLoggedIn(value: false, with: 0)
31+ DataStorage.standard.setIsLoggedIn(value: false, with: 0)
35− self?.didEndSession?()
32+ self?.didEndSession?()
36− }
37 }
33 }
38
34
39− profile.deleteAllSessions = {
35+ profile.onSettings = { [weak self, weak storyboard] in
40− Model.deactivateAll() {
36+ let vc = storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
41− [weak self] in
37+ self?.navigationController?.pushViewController(vc, animated: true)
42−
43− DataStorage.standard.setIsLoggedIn(value: false, with: 0)
44− self?.didEndSession?()
45− }
46 }
38 }
47
39
48− profile.onSettings = { [weak self, weak storyboard, weak profile] in
40+ profile.onChannelsListToAddAPerson = { [weak self, weak storyboard] (user) in
49−
50− let vc = storyboard?.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
41+ let vc = storyboard?.instantiateViewController(withIdentifier: simplifiedChannelsList) as! SimplifiedChannelsList
51− vc.delegate = profile
42+ vc.user = user
52− vc.userActive = profile?.user
53
43
44+ let transition = CATransition()
45+ transition.duration = 0.5
46+ transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
47+ transition.type = CATransitionType.moveIn
48+ transition.subtype = CATransitionSubtype.fromTop
49+ self?.navigationController?.view.layer.add(transition, forKey: nil)
54− self?.navigationController?.pushViewController(vc, animated: true)
50+ self?.navigationController?.pushViewController(vc, animated: false)
55 }
51 }
56−
57−
58 navigationController?.setViewControllers([profile], animated: false)
52 navigationController?.setViewControllers([profile], animated: false)
59 }
53 }
60}
54}
GDproject/Controller/Log In/CodeViewController.swiftdeleted−144
@@ -1,144 +0,0 @@
1−//
2−// CodeViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−
12−class CodeViewController: UIViewController {
13−
14− @IBOutlet weak var f1: UITextField!
15− @IBOutlet weak var f2: UITextField!
16− @IBOutlet weak var f3: UITextField!
17− @IBOutlet weak var f4: UITextField!
18− @IBOutlet weak var f5: UITextField!
19− @IBOutlet weak var f6: UITextField!
20−
21− var loading = UIActivityIndicatorView(style: .gray)
22−
23− var onSuccessLogIn: (()->())?
24−
25− override func viewDidLoad() {
26− super.viewDidLoad()
27− setUpConstraint()
28−
29− navigationItem.title = DataStorage.standard.getEmail()
30−
31− f1.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
32− f2.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
33− f3.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
34− f4.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
35− f5.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
36− f6.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
37− }
38−
39− override func viewWillDisappear(_ animated: Bool) {
40− super.viewWillDisappear(animated)
41−
42− loading.stopAnimating()
43− }
44−
45− override func viewWillAppear(_ animated: Bool) {
46− super.viewWillAppear(animated)
47−
48− f1.becomeFirstResponder()
49− }
50−
51− @objc func textFiledDidChange(textField: UITextField) {
52− let text = textField.text
53−
54− // only 1 char
55− if text?.utf16.count == 1 {
56− switch textField {
57− case f1:
58− f2.becomeFirstResponder()
59− case f2:
60− f3.becomeFirstResponder()
61− case f3:
62− f4.becomeFirstResponder()
63− case f4:
64− f5.becomeFirstResponder()
65− case f5:
66− f6.becomeFirstResponder()
67− case f6:
68− f6.resignFirstResponder()
69− default:
70− break
71− }
72− }
73− }
74−
75−
76− func presentAlertInvalidData(with text: String)
77− {
78− let alert = UIAlertController(title: "Invalid code", message: text, preferredStyle: .alert)
79− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
80− self.present(alert, animated: true, completion: nil)
81−
82− loading.stopAnimating()
83− }
84−
85− @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
86−
87− @IBAction func whereToGoNext(_ sender: UIButton)
88− {
89− guard let f1t = f1.text, let f2t = f2.text, let f3t = f3.text, let f4t = f4.text, let f5t = f5.text, let f6t = f6.text else {
90− presentAlertInvalidData(with: "Some fields are missing");
91− return
92− }
93−
94− if f1t.isEmpty || f2t.isEmpty || f3t.isEmpty || f4t.isEmpty || f5t.isEmpty || f6t.isEmpty {
95− presentAlertInvalidData(with: "Some fields are missing");
96− return
97− }
98−
99− let code = "\(f1.text!)\(f2.text!)\(f3.text!)\(f4.text!)\(f5.text!)\(f6.text!)"
100− if let codeToInt = Int(code)
101− {
102− loading.startAnimating()
103− Model.verify(with: codeToInt) { [weak self] in
104− // if everything is okay we can authemticicate
105− if !$0 {
106− self?.presentAlertInvalidData(with: "Wrong code. Try again!")
107− self?.loading.stopAnimating()
108− return
109− } else {
110− // Model.authemticiateMe
111− Model.authenticateMe { [weak self] (res) in
112− if res {
113− self?.onSuccessLogIn?()
114− }
115− }
116− return
117− }
118− }
119− }
120− }
121−
122− func setUpConstraint()
123− {
124− self.view.addSubview(loading)
125− loading.centerInSuperview()
126− // for keyboard notifications
127− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
128−
129− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
130− }
131−
132− @objc func handleKeyboardNotifications(notification: NSNotification){
133− if let userInfo = notification.userInfo {
134− // UIKeyboardFrameEndUserInfoKey
135− let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
136− bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? keyBoardFrame.height - self.view.safeAreaInsets.bottom : 0
137−
138− UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
139− self.view.layoutIfNeeded()
140− })
141− }
142− }
143−
144−}
GDproject/Controller/Log In/FacultyTableViewController.swiftdeleted−88
@@ -1,88 +0,0 @@
1−//
2−// FacultyTableViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−protocol ChosenFactulty: class {
12− func onChooseFaculty(faculty: Model.Faculty)
13−}
14−
15−class FacultyTableViewController: UITableViewController {
16−
17− weak var delegate: ChosenFactulty?
18−
19− var currentFaculties: [Model.Faculty] = []{
20− didSet {
21− tableView.reloadData()
22− }
23− }
24−
25− var isFiltering: Bool {
26− return searchController.isActive && !searchBarIsEmpty()
27− }
28−
29− func searchBarIsEmpty() -> Bool {
30− return searchController.searchBar.text?.isEmpty ?? true
31− }
32−
33− var searchController = UISearchController(searchResultsController: nil)
34−
35− override func viewDidLoad() {
36− super.viewDidLoad()
37−
38− self.navigationItem.title = "Faculties"
39− self.navigationItem.searchController = searchController
40− self.navigationItem.hidesSearchBarWhenScrolling = false
41− searchController.obscuresBackgroundDuringPresentation = false
42−
43− setUpTimer()
44− }
45−
46− func setUpTimer(){
47− Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { (timer) in
48− DispatchQueue.main.async { [weak self] in
49−
50− if self!.isFiltering {
51− Model.searchFaculty(string: (self?.searchController.searchBar.text)!) { [weak self] in
52− self?.currentFaculties = $0
53− }
54− }
55− }
56− }
57− }
58−
59−
60− // MARK: - Table view data source
61−
62− override func numberOfSections(in tableView: UITableView) -> Int {
63− return 1
64− }
65−
66− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
67− return currentFaculties.count
68− }
69−
70−
71− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
72− {
73− let cell = tableView.dequeueReusableCell(withIdentifier: "F", for: indexPath)
74−
75− cell.textLabel?.text = currentFaculties[indexPath.row].name
76− cell.detailTextLabel?.text = currentFaculties[indexPath.row].campusName
77− cell.selectionStyle = .none
78−
79− return cell
80− }
81−
82− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
83− delegate?.onChooseFaculty(faculty: currentFaculties[indexPath.row])
84− searchController.dismiss(animated: true, completion: nil)
85− self.navigationController?.popViewController(animated: true)
86− }
87−
88−}
GDproject/Controller/Log In/InititalsViewCell.swiftdeleted−23
@@ -1,23 +0,0 @@
1−//
2−// InititalsViewCell.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class InititalsViewCell: UITableViewCell {
12−
13− @IBOutlet weak var initialsTextField: UITextField!
14−
15− override func awakeFromNib() {
16− super.awakeFromNib()
17− // Initialization code
18− }
19−
20− func fill(with name: String){
21− initialsTextField.text = name
22− }
23−}
GDproject/Controller/Log In/LogInCoordinator1.swiftnew file+48
@@ -0,0 +1,48 @@
1+////
2+//// LogInCoordinator.swift
3+//// GDproject
4+////
5+//// Created by cstore on 23/02/2019.
6+//// Copyright © 2019 drHSE. All rights reserved.
7+////
8+//
9+//import UIKit
10+//
11+//class LogInCoordinator{
12+//
13+// private weak var navigationController: UINavigationController?
14+// private var window: UIWindow!
15+// // MARK:- Init
16+// init(navigationController: UINavigationController, window: UIWindow) {
17+// self.navigationController = navigationController
18+// self.window = window
19+// }
20+//
21+// func start(){
22+// showLogInPage()
23+// }
24+//
25+// // MARK: - Private implementation
26+//// private func showStatusPage(){
27+//// let controller = TabbarCoordinator(window: window)
28+//// controller.start()
29+//// }
30+//
31+// private func showLogInPage(){
32+// let controller = UIStoryboard.makeLogIn()
33+//
34+// controller.onLogIn = {
35+// (id) in Model.authenticate(with: id) {
36+// (res) in
37+//
38+// if (res) { DataStorage.standard.setUserKey(with: id) }
39+// else { DataStorage.standard.setUserKey(with: 0) }
40+//
41+// controller.authenticateSucceeded = res
42+// }
43+// }
44+//
45+// navigationController?.pushViewController(controller, animated: false)
46+// }
47+//
48+//}
GDproject/Controller/Log In/LogInViewController.swift+4−29
@@ -14,24 +14,7 @@ import Result
14
14
15class LogInViewController: UIViewController {
15class LogInViewController: UIViewController {
16
16
17− var loading = UIActivityIndicatorView(style: .gray)
18−
19− var authenticate: ((String)->())?
17+ var authenticate: ((Int)->())?
20−
21− func presentAlertInvalidCode()
22− {
23− let alert = UIAlertController(title: "Invalid email", message: "Try again. Use @hse.ru mail.", preferredStyle: .alert)
24− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
25− self.present(alert, animated: true, completion: nil)
26− mailTextField.text = ""
27− loading.stopAnimating()
28− }
29−
30− override func viewWillDisappear(_ animated: Bool) {
31− super.viewWillDisappear(animated)
32−
33− loading.stopAnimating()
34− }
35
18
36 let logInLabel: UILabel = {
19 let logInLabel: UILabel = {
37 let label = UILabel()
20 let label = UILabel()
@@ -47,8 +30,6 @@ class LogInViewController: UIViewController {
47 textField.placeholder = "Mail"
30 textField.placeholder = "Mail"
48 textField.borderStyle = .roundedRect
31 textField.borderStyle = .roundedRect
49 textField.textColor = .black
32 textField.textColor = .black
50− textField.autocorrectionType = UITextAutocorrectionType.no
51− textField.autocapitalizationType = UITextAutocapitalizationType.none
52 textField.clearButtonMode = .always
33 textField.clearButtonMode = .always
53 return textField
34 return textField
54 }()
35 }()
@@ -64,8 +45,7 @@ class LogInViewController: UIViewController {
64 }()
45 }()
65
46
66 @objc func handleTap(){
47 @objc func handleTap(){
67− loading.startAnimating()
68− authenticate?(mailTextField.text!)
48+ authenticate?(Int(mailTextField.text!)!)
69 }
49 }
70
50
71 private lazy var keyboardBar = UIView()
51 private lazy var keyboardBar = UIView()
@@ -75,10 +55,6 @@ class LogInViewController: UIViewController {
75 func setUpView(){
55 func setUpView(){
76 // logIn stack with textField and label
56 // logIn stack with textField and label
77 view.addSubview(contentView)
57 view.addSubview(contentView)
78− view.addSubview(loading)
79−
80− loading.centerInSuperview()
81−
82 contentView.edgesToSuperview(excluding: .bottom, insets: .left(16) + .right(16) + .top(80), usingSafeArea: true)
58 contentView.edgesToSuperview(excluding: .bottom, insets: .left(16) + .right(16) + .top(80), usingSafeArea: true)
83 let views = [logInLabel, mailTextField]
59 let views = [logInLabel, mailTextField]
84 contentView.stack(views, axis: .vertical, spacing: 10)
60 contentView.stack(views, axis: .vertical, spacing: 10)
@@ -86,7 +62,6 @@ class LogInViewController: UIViewController {
86
62
87 func configureKeyboard(){
63 func configureKeyboard(){
88
64
89− mailTextField.keyboardType = .emailAddress
90 // configure keyboardBar setUp
65 // configure keyboardBar setUp
91 view.addSubview(keyboardBar)
66 view.addSubview(keyboardBar)
92 keyboardBar.height(50)
67 keyboardBar.height(50)
@@ -97,14 +72,14 @@ class LogInViewController: UIViewController {
97 // configure keyboardBar components
72 // configure keyboardBar components
98 keyboardBar.addSubview(logInButton)
73 keyboardBar.addSubview(logInButton)
99 logInButton.height(50)
74 logInButton.height(50)
100− logInButton.rightToSuperview(view.rightAnchor, offset: -16, relation: .equal, isActive: true)
75+ logInButton.leftToSuperview(view.leftAnchor, offset: 16, relation: .equal, isActive: true)
101
76
102 }
77 }
103
78
104 func logicOfLogInInputValidation() -> ((String?)->()) {
79 func logicOfLogInInputValidation() -> ((String?)->()) {
105
80
106 let logic: ((String?)->()) = { [weak self] (someText) in
81 let logic: ((String?)->()) = { [weak self] (someText) in
107− if let text = someText, !text.isEmpty, text.contains("@") {
82+ if let text = someText, !text.isEmpty, let _ = Int(text) {
108 self?.logInButton.isEnabled = true
83 self?.logInButton.isEnabled = true
109 } else {
84 } else {
110 self?.logInButton.isEnabled = false
85 self?.logInButton.isEnabled = false
GDproject/Controller/Log In/RegisterTableViewController.swiftdeleted−198
@@ -1,198 +0,0 @@
1−//
2−// RegisterTableViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class RegisterTableViewController: UITableViewController, ChosenFactulty
12−{
13−
14− func presentAlertInvalidData(message: String)
15− {
16− let alert = UIAlertController(title: "Invalid data", message: message, preferredStyle: .alert)
17− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
18− self.present(alert, animated: true, completion: nil)
19− }
20−
21− func onChooseFaculty(faculty: Model.Faculty) {
22− self.faculty = faculty
23− tableView.reloadData()
24− }
25−
26− weak var delegate: UpdateUser?
27−
28− var onRegistration: (()->())?
29−
30− var faculty: Model.Faculty?
31− var user: Model.NewRegistration = Model.NewRegistration(email: DataStorage.standard.getEmail()!, firstName: nil, middleName: nil, lastName: nil, faculty: nil)
32−
33− var userActive: Model.Users? {
34− didSet {
35− if let userA = userActive {
36− user.firstName = userA.firstName
37− user.middleName = userA.middleName
38− user.lastName = userA.lastName
39−
40− faculty = userA.faculty
41− self.updateUserIfCan = true
42− tableView.reloadData()
43− }
44− }
45− }
46−
47− var updateUserIfCan: Bool = false
48−
49− override func viewDidLoad()
50− {
51− super.viewDidLoad()
52−
53− navigationItem.largeTitleDisplayMode = .never
54− tableView.keyboardDismissMode = .interactive
55− navigationItem.title = user.email
56− navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(endRegistration))
57− }
58−
59−
60− @objc func endRegistration()
61− {
62− let fieldsMissing = "Some fields are missing. Add more information"
63− updateUser()
64− guard let faculty = faculty else { presentAlertInvalidData(message: fieldsMissing); return }
65−
66− user.faculty = faculty.url
67−
68− guard let name = user.firstName else { presentAlertInvalidData(message: fieldsMissing); return }
69− guard let middle = user.middleName else { presentAlertInvalidData(message: fieldsMissing); return }
70− guard let last = user.lastName else { presentAlertInvalidData(message: fieldsMissing); return }
71−
72− if updateUserIfCan {
73− guard let delegate = delegate else { return }
74− guard var userA = userActive else { return }
75−
76− // updating current
77− userA.firstName = name
78− userA.faculty = faculty
79− userA.middleName = middle
80− userA.lastName = last
81−
82− Model.userUpdate(with: user) { [weak self] in
83−
84− if $0 {
85− delegate.updateUserObj(with: userA)
86− self?.navigationController?.popViewController(animated: true)
87− } else {
88− self?.presentAlertInvalidData(message: "Something went wrong! Try again")
89− }
90−
91− }
92− } else {
93−
94− Model.register(object: user)
95− { [weak self] in
96− self?.onRegistration?()
97− }
98− }
99− }
100− // MARK: - Table view data source
101−
102− override func numberOfSections(in tableView: UITableView) -> Int {
103− return 2
104− }
105−
106− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
107−
108− switch section {
109− case 0:
110− return 3
111− default:
112− if let _ = faculty {
113− return 2
114− } else {
115− return 1
116− }
117− }
118− }
119−
120− override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
121− {
122− switch section {
123− case 0:
124− return "Initials"
125− default:
126− return "Faculty"
127− }
128− }
129−
130−
131− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
132− {
133− switch indexPath.section {
134− case 0:
135− let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! InititalsViewCell
136− switch indexPath.row{
137− case 0:
138− if let name = user.firstName {
139− cell.fill(with: name)
140− } else {
141− cell.initialsTextField.placeholder = "First name"
142− }
143− case 1:
144− if let name = user.middleName {
145− cell.fill(with: name)
146− } else {
147− cell.initialsTextField.placeholder = "Middle name"
148− }
149− default:
150− if let name = user.lastName {
151− cell.fill(with: name)
152− } else {
153− cell.initialsTextField.placeholder = "Last name"
154− }
155− }
156− cell.selectionStyle = .none
157− return cell
158− default:
159− switch indexPath.row {
160− case 0:
161− let cell = tableView.dequeueReusableCell(withIdentifier: "cell111", for: indexPath)
162− cell.selectionStyle = .none
163− return cell
164− default:
165− let cell = tableView.dequeueReusableCell(withIdentifier: "facultyCell", for: indexPath)
166− cell.textLabel?.text = faculty!.name
167− cell.detailTextLabel?.text = faculty!.campusName
168− cell.selectionStyle = .none
169− return cell
170− }
171− }
172− }
173−
174−
175− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
176− if indexPath.section == 1 && indexPath.row == 0 {
177−
178− updateUser()
179−
180− let vc = storyboard?.instantiateViewController(withIdentifier: "FacultyTableViewController") as! FacultyTableViewController
181−
182− vc.delegate = self
183−
184− self.navigationController?.pushViewController(vc, animated: true)
185− }
186− }
187−
188− func updateUser(){
189− guard let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as? InititalsViewCell else {return}
190− guard let cell1 = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? InititalsViewCell else {return}
191− guard let cell2 = tableView.cellForRow(at: IndexPath(row: 2, section: 0)) as? InititalsViewCell else {return}
192−
193− user.firstName = cell.initialsTextField.text!
194− user.middleName = cell1.initialsTextField.text!
195− user.lastName = cell2.initialsTextField.text!
196− }
197−
198−}
GDproject/Controller/Messages/ChatInfoViewController.swiftdeleted−308
@@ -1,308 +0,0 @@
1−//
2−// ChatInfoViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 02/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−/// Class for displaying chat info
12−///
13−class ChatInfoViewController: UITableViewController {
14−
15− enum PersonStatus{
16− case admin
17− case ordinary
18− }
19−
20− weak var delegate: UpdatableGroup?
21−
22− var groupChat: Model.Group? {
23− didSet{
24− if let groupChat = groupChat {
25− usersArray = groupChat.users.map { $0.key }
26− }
27− }
28− }
29−
30− var usersArray: [Int] = [] {
31− didSet {
32− tableView.reloadData()
33− }
34− }
35−
36− var users: [Int: Model.Users] = [:]
37−
38− func canIEditThisChat() -> PersonStatus
39− {
40− let myId = UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
41−
42− if let groupChatUserPermission = groupChat?.users[myId]?.isAdmin {
43− return groupChatUserPermission ? .admin : .ordinary
44− }
45−
46− return .ordinary
47− }
48−
49− var myPermissions: PersonStatus = .ordinary
50−
51−
52−
53− override func viewDidLoad() {
54− super.viewDidLoad()
55−
56− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
57− myPermissions = canIEditThisChat()
58− tableView.reloadData()
59−
60− switch myPermissions {
61− case .admin:
62− navigationItem.rightBarButtonItem = self.editButtonItem
63− default:
64− return
65− }
66− }
67−
68− // MARK: - Table view data source
69−
70− override func numberOfSections(in tableView: UITableView) -> Int {
71− return 3
72− }
73−
74− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
75− switch section {
76− case 0:
77− return 1
78− case 1:
79− return 1
80− default:
81− return usersArray.count + (myPermissions == .ordinary ? 0 : 1)
82− }
83− }
84−
85−
86− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
87− {
88− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
89−
90− if indexPath.row == 0 {
91− switch indexPath.section {
92− case 0:
93− cell.textLabel?.text = groupChat!.name
94− cell.selectionStyle = .none
95− return cell
96− case 1:
97− cell.textLabel?.text = "Leave chat"
98− cell.textLabel?.textColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
99− cell.selectionStyle = .none
100− return cell
101− default:
102− switch myPermissions{
103− case .admin:
104− cell.textLabel?.text = "Add participants"
105− cell.accessoryType = .disclosureIndicator
106− case .ordinary:
107− cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
108− }
109− cell.selectionStyle = .none
110− return cell
111− }
112− }
113−
114− switch myPermissions{
115− case .admin:
116− cell.textLabel?.text = name(for: users[usersArray[indexPath.row-1]])
117− case .ordinary:
118− cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
119− }
120− cell.selectionStyle = .none
121− return cell
122− }
123−
124− private func name(for user: Model.Users?) -> String {
125− if let user = user, let perm = groupChat?.users[user.id]?.isAdmin {
126− if perm {
127− return "🤴🏻 \(user.fullName())"
128− }
129− return "👤 \(user.fullName())"
130− }
131−
132− return "left"
133− }
134−
135− override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
136− {
137− switch section {
138− case 0:
139− return "Title"
140− case 1:
141− return "Opportunities"
142− default:
143− return "Participants"
144− }
145− }
146−
147−
148− func editName(for cell: UITableViewCell){
149− let alert = UIAlertController(title: "Are you sure?", message: "Title:", preferredStyle: .alert)
150−
151− let action1 = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
152−
153− alert.addTextField { [weak self] (tf) in
154− tf.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
155− tf.text = self?.groupChat?.name
156− }
157−
158− let action2 = UIAlertAction(title: "OK", style: .default) { [unowned self] _ in
159− let name = alert.textFields?.first?.text
160− cell.textLabel?.text = name
161− self.groupChat?.name = name!
162− Model.updateGroupChat(with: self.groupChat!)
163− self.delegate?.updateGroup(with: self.groupChat!)
164− }
165−
166− alert.addAction(action1)
167− alert.addAction(action2)
168−
169− present(alert, animated: true, completion: nil)
170− }
171− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
172− {
173− guard let groupChat = groupChat else {
174− return
175− }
176−
177− guard let cell = tableView.cellForRow(at: indexPath) else {
178− return
179− }
180−
181− if indexPath.row == 0 {
182− switch indexPath.section{
183− case 0:
184− switch myPermissions{
185− case .admin:
186− editName(for: cell)
187− default:
188− break
189− }
190− case 1:
191− Model.leaveGroupChat(id: groupChat.id) {
192− [weak self] in
193− self?.navigationController?.popViewController(animated: true)
194− }
195− default:
196− switch myPermissions{
197− case .admin:
198− showUserChoiceVC()
199− default:
200− showParticipantPage(with: usersArray[indexPath.row])
201− }
202− }
203− }
204−
205−
206− if indexPath.section == 2 && indexPath.row != 0 {
207− switch myPermissions{
208− case .admin:
209− showParticipantPage(with: usersArray[indexPath.row-1])
210− default:
211− showParticipantPage(with: usersArray[indexPath.row])
212− }
213− }
214− }
215−
216− var onUserDiplay: ((Int)->())?
217−
218− func showParticipantPage(with user: Int?) {
219− if let user = user {
220− onUserDiplay?(user)
221− }
222− }
223−
224− func showUserChoiceVC()
225− {
226− let vc = storyboard?.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
227−
228− vc.whatToDoWithSelection = { [weak self, weak vc] mapa in
229−
230− mapa.forEach { self?.users[$0.key] = Model.Channels.fullPeopleDict[$0.key] }
231− mapa.forEach { self?.groupChat?.users[$0.key] = $0.value }
232− vc?.navigationController?.popViewController(animated: true)
233− }
234−
235− navigationController?.pushViewController(vc, animated: true)
236− }
237−
238− override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
239− {
240− if editingStyle == UITableViewCell.EditingStyle.delete {
241− groupChat?.users[usersArray[indexPath.row-1]] = nil
242− }
243−
244− tableView.reloadData()
245− }
246−
247− override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
248− if indexPath.row == 0 {
249− return false
250− }
251−
252− return true
253− }
254−
255− override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
256− {
257− let editButton = UITableViewRowAction(style: .normal, title: "Promote") { [unowned self] (rowAction, indexPath) in
258−
259− self.tableView.beginUpdates()
260− self.groupChat?.users[self.usersArray[indexPath.row-1]]?.isAdmin = true
261− self.tableView.reloadRows(at: [indexPath], with: .none)
262− self.tableView.endUpdates()
263− }
264−
265− editButton.backgroundColor = #colorLiteral(red: 0.476841867, green: 0.5048075914, blue: 1, alpha: 1)
266−
267− let restrictButton = UITableViewRowAction(style: .normal, title: "Restrict") { [unowned self] (rowAction, indexPath) in
268−
269− self.tableView.beginUpdates()
270− self.groupChat?.users[self.usersArray[indexPath.row-1]]?.isAdmin = false
271− self.tableView.reloadRows(at: [indexPath], with: .none)
272− self.tableView.endUpdates()
273− }
274−
275− restrictButton.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
276−
277− let deleteButton = UITableViewRowAction(style: .normal, title: "Delete") { [unowned self] (action, indexPath) in
278−
279− self.tableView.beginUpdates()
280− self.groupChat?.users[self.usersArray[indexPath.row-1]] = nil
281− self.tableView.deleteRows(at: [indexPath], with: .none)
282− self.tableView.endUpdates()
283− }
284−
285− deleteButton.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
286−
287− return [editButton, restrictButton, deleteButton]
288− }
289−
290− /// update chatInfo
291− override func viewWillDisappear(_ animated: Bool) {
292−
293− defer {
294− super.viewWillDisappear(animated)
295− }
296−
297− guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else {
298− switch myPermissions {
299− case .ordinary:
300− return
301− case .admin:
302− Model.updateGroupChat(with: groupChat!)
303− delegate?.updateGroup(with: groupChat!)
304− }
305− return
306− }
307− }
308−}
GDproject/Controller/Messages/Dialog/DialogCell.swiftdeleted−132
@@ -1,132 +0,0 @@
1−//
2−// DialogCell.swift
3−// GDproject
4−//
5−// Created by cstore on 05/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−import MarkdownKit
12−
13−class DialogCell: UITableViewCell {
14−
15− let nameLabel: UIButton = {
16− let button = UIButton()
17− button.setTitleColor(.black, for: .normal)
18− button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
19− button.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left
20− return button
21− }()
22−
23− @objc func displayProfile()
24− {
25− if let id = self.user?.id {
26− print("diplay")
27− onUserDisplay?(id)
28− }
29− }
30−
31− var onUserDisplay: ((Int)->())?
32−
33−
34− let timeLabel: UILabel = {
35− let label = UILabel()
36− label.font = UIFont.systemFont(ofSize: 9)
37− label.textAlignment = NSTextAlignment.right
38− label.textColor = #colorLiteral(red: 0.4352941176, green: 0.4431372549, blue: 0.4745098039, alpha: 1)
39− return label
40− }()
41−
42− func createTextView(with text: NSAttributedString, _ isSelectable: Bool) -> UITextView
43− {
44− let textView = UITextView()
45− textView.isScrollEnabled = false
46− textView.isEditable = false
47− textView.sizeToFit()
48−
49− if isSelectable {
50− textView.isSelectable = true
51− } else {
52− textView.isUserInteractionEnabled = false
53− }
54−
55− textView.attributedText = text
56− return textView
57− }
58−
59− override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
60− {
61− super.init(style: style, reuseIdentifier: reuseIdentifier)
62− }
63−
64− required init?(coder aDecoder: NSCoder)
65− {
66− fatalError("init(coder:) has not been implemented")
67− }
68−
69− var user: Model.Users? {
70− didSet{
71− nameLabel.setTitle(user!.fullName(), for: .normal)
72− }
73− }
74−
75− var textView: UITextView!
76−
77− func fill(with markdownText: NSAttributedString, byUser: Model.Users, when: String)
78− {
79− let myId = DataStorage.standard.getUserId()
80− // important
81− contentView.subviews.forEach({ $0.removeFromSuperview() })
82−
83− nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
84−
85− self.user = byUser
86− textView = createTextView(with: markdownText, true)
87− textView.layer.cornerRadius = 10
88− textView.clipsToBounds = true
89−
90− self.contentView.addSubview(textView)
91− self.contentView.addSubview(timeLabel)
92−
93− timeLabel.text = when.getDate()
94− textView.width(min: 50, max: self.contentView.bounds.width-70, priority: .required, isActive: true)
95−
96− if myId == byUser.id
97− {
98− layoutMyMessage()
99− } else {
100− layOutOtherMessage()
101− }
102− }
103−
104− func layOutOtherMessage(){
105− self.contentView.addSubview(nameLabel)
106−
107− nameLabel.setTitle(user!.fullName(), for: .normal)
108−
109− nameLabel.edgesToSuperview(excluding: .bottom, insets: .top(4) + .left(8))
110− textView.edgesToSuperview(excluding: [.top, .right] , insets: .left(8) + .bottom(20))
111− textView.topToBottom(of: nameLabel)
112−
113− textView.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
114− textView.textColor = .white
115− timeLabel.edgesToSuperview(excluding: .top, insets: .right(70) + .left(8))
116− timeLabel.topToBottom(of: textView, offset: 4)
117− timeLabel.textAlignment = .left
118− }
119−
120− func layoutMyMessage()
121− {
122− textView.edgesToSuperview(excluding: .left, insets: .right(8) + .bottom(20) + .top(4))
123− textView.backgroundColor = UIColor(red:0.08, green:0.49, blue:0.98, alpha:1.0)
124− textView.textColor = .white
125− timeLabel.edgesToSuperview(excluding: .top, insets: .left(70) + .right(8))
126− timeLabel.topToBottom(of: textView, offset: 4)
127− timeLabel.textAlignment = .right
128− }
129−}
130−
131−
132−
GDproject/Controller/Messages/Dialog/DialogViewController.swiftdeleted−340
@@ -1,340 +0,0 @@
1−//
2−// DialogViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 01/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−import Marklight
12−
13−protocol UpdatableGroup:class {
14− func updateGroup(with group: Model.Group)
15−}
16−
17−class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegate, UITableViewDataSource
18−{
19− var onUserDisplay: ((Int)->())?
20−
21− var tableView: UITableView = UITableView()
22−
23− func updateGroup(with group: Model.Group){
24− self.groupChat?.group = group
25− setTitleForGroup(groupChat: groupChat!)
26− }
27−
28− let cellId = "cell3"
29− var onInfoShow: (()->())?
30−
31− var dialog: Model.Dialog? {
32− didSet{
33− switch dialog! {
34− case .groupChat(let chat):
35− self.groupChat = chat
36− case .userChat(let chat):
37− self.userChat = chat
38− }
39− }
40− }
41−
42− var groupChat: Model.GroupChat?
43− var userChat: Model.UserChat?
44−
45− var users: [Int: Model.Users]?
46−
47− var groupId: Int?
48−
49− var cellData: [PostCellData] = [] {
50− didSet {
51− tableView.reloadData()
52− canBePaginated = true
53− }
54− }
55−
56− override func viewDidLoad() {
57− super.viewDidLoad()
58−
59− setConstraints()
60− magicForKeyboardChanges()
61−
62− self.tableView.delegate = self
63− self.tableView.dataSource = self
64−
65− tableView.setContentOffset(CGPoint(x: 0, y: 50), animated: false)
66−
67− navigationItem.largeTitleDisplayMode = .never
68−
69− tableView.keyboardDismissMode = .onDrag
70− tableView.separatorStyle = .none
71− tableView.register(DialogCell.self, forCellReuseIdentifier: cellId)
72− tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
73− tableView.contentInsetAdjustmentBehavior = .never
74− tableView.contentOffset = CGPoint(x: 0, y: 30)
75−
76− if let groupChat = groupChat {
77− setTitleForGroup(groupChat: groupChat)
78− } else if let userChat = userChat{
79− setTitleForChat(userChat: userChat)
80− }
81− }
82−
83− var messageSendView: UIView = {
84− let view = UIView()
85− view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
86− return view
87− }()
88−
89− var messageTextView: UITextView =
90− {
91− let textStorage = MarklightTextStorage()
92− textStorage.marklightTextProcessor.codeColor = UIColor.orange
93− textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
94− textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
95− textStorage.marklightTextProcessor.codeFontName = "Courier"
96− textStorage.marklightTextProcessor.fontTextStyle = UIFont.TextStyle.subheadline.rawValue
97− textStorage.marklightTextProcessor.hideSyntax = false
98−
99− let layoutManager = NSLayoutManager()
100−
101− // Assign the `UITextView`'s `NSLayoutManager` to the `NSTextStorage` subclass
102− //textStorage.addLayoutManager(textView.layoutManager)
103− textStorage.addLayoutManager(layoutManager)
104−
105− let textContainer = NSTextContainer()
106− layoutManager.addTextContainer(textContainer)
107−
108− let textView = UITextView(frame: CGRect.zero, textContainer: textContainer)
109− textView.isEditable = true
110− textView.isScrollEnabled = true
111− textView.backgroundColor = .white
112− return textView
113− }()
114−
115− var sendButton: UIButton = {
116− let button = UIButton()
117− button.setTitle("Send", for: .normal)
118− button.setTitleColor(.blue, for: .normal)
119− button.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
120− button.addTarget(self, action: #selector(sendMessage), for: .touchUpInside)
121− return button
122− }()
123−
124− @objc func sendMessage()
125− {
126− var destination: Model.MessageDestination?
127−
128− if let group = groupChat {
129− destination = Model.MessageDestination.groupChatDestination(group.group.id)
130− } else if let user = userChat {
131− destination = Model.MessageDestination.userChatDestination(user.user)
132− }
133−
134− if let destination = destination
135− {
136− Model.sendMessage(message: Model.SendMessage(body: Model.Attachments(markdown: messageTextView.text), destination: destination)) { [unowned self] in
137−
138− switch $0 {
139− case .success, .success1:
140− self.getMessagesNew(for: self.dialog!)
141− self.messageTextView.text = ""
142− default:
143− self.showAlertOn(result: $0)
144− }
145− }
146−
147− prevLast = -1
148− }
149− }
150−
151− var lineView: UIView = {
152− let view = UIView()
153− view.backgroundColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
154− return view
155− }()
156−
157− var bottomConstraint: NSLayoutConstraint!
158−
159− func setConstraints(){
160− self.view.addSubview(tableView)
161− self.view.addSubview(messageSendView)
162−
163− messageSendView.addSubview(messageTextView)
164− messageSendView.addSubview(sendButton)
165− messageSendView.addSubview(lineView)
166−
167− messageSendView.edgesToSuperview(excluding: [.top,.bottom])
168−
169− bottomConstraint = NSLayoutConstraint(item: messageSendView, attribute: .bottom, relatedBy: .equal, toItem: self.view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
170− view.addConstraint(bottomConstraint)
171−
172− messageSendView.height(60)
173−
174− sendButton.edgesToSuperview(excluding: .left)
175− sendButton.width(60)
176−
177− lineView.edgesToSuperview(excluding: .bottom)
178− lineView.height(0.5)
179−
180− messageTextView.edgesToSuperview(excluding: .right)
181− messageTextView.rightToLeft(of: sendButton)
182−
183− tableView.edgesToSuperview(excluding: .bottom)
184− tableView.bottomToTop(of: messageSendView)
185−
186− self.view.layoutSubviews()
187− }
188−
189− func magicForKeyboardChanges()
190− {
191− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
192−
193− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
194− }
195−
196− @objc func handleKeyboardNotifications(notification: NSNotification){
197− if let userInfo = notification.userInfo{
198− // UIKeyboardFrameEndUserInfoKey
199−
200− let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
201−
202− bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? -(keyBoardFrame.height) + self.view.safeAreaInsets.bottom : 0
203−
204− UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
205− self.view.layoutIfNeeded()
206− }) { (completed) in
207−
208− }
209− }
210− }
211−
212− func setTitleForChat(userChat: Model.UserChat){
213− navigationItem.title = "\(users![userChat.user]!.fullName())"
214− navigationItem.rightBarButtonItem = UIBarButtonItem(title: "👤", style: .plain, target: self, action: #selector(showPersonPage))
215− }
216−
217− @objc func showPersonPage(){
218− if let id = userChat?.user{
219− onUserDisplay?(id)
220− }
221− }
222−
223− func setTitleForGroup(groupChat: Model.GroupChat){
224− navigationItem.title = "\(groupChat.group.name)"
225− navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Info", style: .plain, target: self, action: #selector(moveToInfoVC))
226− }
227−
228− // onInfoShow
229− @objc func moveToInfoVC(){
230− let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: chatInfoViewController) as! ChatInfoViewController
231−
232− vc.delegate = self
233− vc.users = users!
234− vc.onUserDiplay = onUserDisplay
235−
236− if let groupChat = groupChat {
237− vc.groupChat = groupChat.group
238− }
239−
240− navigationController?.pushViewController(vc, animated: true)
241− }
242−
243− var currentMessagesInChat: [Model.LastMessage] = [] {
244− didSet
245− {
246− cellData = currentMessagesInChat.map { PostCellData(attributedData: PostCellData.create(with: [$0.body])) }
247− }
248− }
249−
250− // MARK: - Table view data source
251−
252− func numberOfSections(in tableView: UITableView) -> Int {
253− return 1
254− }
255−
256− func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
257− return cellData.count
258− }
259−
260− override func viewWillAppear(_ animated: Bool)
261− {
262− super.viewWillAppear(animated)
263− tabBarController?.tabBar.isHidden = true
264−
265− if let dialog = dialog {
266− getMessagesNew(for: dialog)
267− }
268− }
269−
270− func getMessages(for dialog: Model.Dialog, starting from: Int? = nil)
271− {
272− switch dialog {
273− case .groupChat(let groupChat):
274− Model.getMessagesFor(typeOfChat: Model.Dialog.groupChat(groupChat), chat: groupChat.group.id, exclusiveFrom: from)
275− { [weak self] in
276− self?.currentMessagesInChat.append(contentsOf: $0)
277− }
278− case .userChat(let userChat):
279− Model.getMessagesFor(typeOfChat: Model.Dialog.userChat(userChat), chat: userChat.user, exclusiveFrom: from)
280− { [weak self] in
281− self?.currentMessagesInChat.append(contentsOf: $0)
282− }
283− }
284− }
285−
286−
287− func getMessagesNew(for dialog: Model.Dialog, starting from: Int? = nil)
288− {
289− switch dialog {
290− case .groupChat(let groupChat):
291− Model.getMessagesFor(typeOfChat: Model.Dialog.groupChat(groupChat), chat: groupChat.group.id, exclusiveFrom: from)
292− { [weak self] in
293− self?.currentMessagesInChat = $0
294− }
295− case .userChat(let userChat):
296− Model.getMessagesFor(typeOfChat: Model.Dialog.userChat(userChat), chat: userChat.user, exclusiveFrom: from)
297− { [weak self] in
298− self?.currentMessagesInChat = $0
299− }
300− }
301− }
302−
303− func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
304− {
305− let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! DialogCell
306−
307− //In cellForRowAtIndexPath
308− cell.transform = CGAffineTransform(scaleX: 1, y: -1)
309− cell.selectionStyle = .none
310−
311−
312− if let user = users?[currentMessagesInChat[indexPath.row].author]
313− {
314− cell.fill(with: cellData[indexPath.row].attributedData, byUser: user, when: currentMessagesInChat[indexPath.row].time)
315−
316− cell.onUserDisplay = onUserDisplay
317− }
318−
319− return cell
320− }
321−
322− var prevLast = -1
323− var canBePaginated = false
324− func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
325− {
326− if indexPath.row == cellData.count - 1 && prevLast != indexPath.row && canBePaginated && cellData.count >= 24
327− {
328− print("exclusiveFrom \(currentMessagesInChat.last?.id ?? 0)")
329− if let dialog = dialog
330− {
331− getMessages(for: dialog, starting: currentMessagesInChat.last?.id)
332− }
333−
334− prevLast = indexPath.row
335− }
336− }
337−}
338−
339−
340−
GDproject/Controller/Messages/DialogViewController.swiftnew file+90
@@ -0,0 +1,90 @@
1+//
2+// DialogViewController.swift
3+// GDproject
4+//
5+// Created by cstore on 01/05/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class DialogViewController: UITableViewController {
12+
13+ var currentDialog: (id: Int, name: String)?
14+
15+ override func viewDidLoad() {
16+ super.viewDidLoad()
17+
18+ if let person = currentDialog {
19+ navigationItem.title = person.name
20+ }
21+ }
22+
23+ // MARK: - Table view data source
24+
25+ override func numberOfSections(in tableView: UITableView) -> Int {
26+ // #warning Incomplete implementation, return the number of sections
27+ return 0
28+ }
29+
30+ override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
31+ // #warning Incomplete implementation, return the number of rows
32+ return 0
33+ }
34+
35+ /*
36+ override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
37+ let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
38+
39+ // Configure the cell...
40+
41+ return cell
42+ }
43+ */
44+
45+ /*
46+ // Override to support conditional editing of the table view.
47+ override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
48+ // Return false if you do not want the specified item to be editable.
49+ return true
50+ }
51+ */
52+
53+ /*
54+ // Override to support editing the table view.
55+ override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
56+ if editingStyle == .delete {
57+ // Delete the row from the data source
58+ tableView.deleteRows(at: [indexPath], with: .fade)
59+ } else if editingStyle == .insert {
60+ // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
61+ }
62+ }
63+ */
64+
65+ /*
66+ // Override to support rearranging the table view.
67+ override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
68+
69+ }
70+ */
71+
72+ /*
73+ // Override to support conditional rearranging of the table view.
74+ override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
75+ // Return false if you do not want the item to be re-orderable.
76+ return true
77+ }
78+ */
79+
80+ /*
81+ // MARK: - Navigation
82+
83+ // In a storyboard-based application, you will often want to do a little preparation before navigation
84+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
85+ // Get the new view controller using segue.destination.
86+ // Pass the selected object to the new view controller.
87+ }
88+ */
89+
90+}
GDproject/Controller/Messages/MessageViewCell.swiftdeleted−38
@@ -1,38 +0,0 @@
1−//
2−// MessageViewCell.swift
3−// GDproject
4−//
5−// Created by cstore on 13/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class MessageViewCell: UITableViewCell {
12−
13− @IBOutlet weak var dialogName: UILabel!
14−
15− @IBOutlet weak var lastMessagePreview: UILabel!
16−
17− @IBOutlet weak var dateLabel: UILabel!
18−
19− override func awakeFromNib() {
20− super.awakeFromNib()
21− // Initialization code
22− }
23−
24− func fill(with dialog: Model.Dialog, user: Model.Users? = nil)
25− {
26− switch dialog {
27−
28− case .groupChat(let group):
29− dialogName.text = group.group.name
30− lastMessagePreview.text = group.lastMessage?.body.markdown
31− dateLabel.text = group.lastMessage?.time.getDate()
32− case .userChat(let userChat):
33− dialogName.text = "👤 \(user!.fullName())"
34− lastMessagePreview.text = userChat.lastMessage?.body.markdown
35− dateLabel.text = userChat.lastMessage?.time.getDate()
36− }
37− }
38−}
GDproject/Controller/Messages/MessagesViewController.swift+54−122
@@ -8,85 +8,26 @@
8
8
9import UIKit
9import UIKit
10
10
11−protocol SelectableDialog: class {
11+class MessagesViewController: UITableViewController {
12− func openDialog(with dialog: Model.Dialog)
13−}
14
12
15−class MessagesViewController: UITableViewController, UISearchControllerDelegate, UISearchResultsUpdating, SelectableDialog {
16−
17− func openDialog(with dialog: Model.Dialog) {
18− onDialogDisplay?((dialog, users))
19− }
20−
21− func updateSearchResults(for searchController: UISearchController) {
22−
23− let filteredData = currentActiveDialogs
24− let inputText = searchController.searchBar.text ?? ""
25−
26− let filteredResults = filteredData.filter {
27−
28− switch $0 {
29− case .groupChat(let gropuChat):
30− return gropuChat.group.name.contains(inputText)
31−
32− case .userChat(let userChat):
33− let user = users[userChat.user]
34− guard let u = user else { return false }
35− return u.fullName().contains(inputText)
36−
37− }
38−
39− }
40−
41− // Apply the filtered results to the search results table.
42− if let resultsController = searchController.searchResultsController as? SuggestedDialogsTableViewController {
43− resultsController.users = users
44− resultsController.currentDialogs = filteredResults
45− resultsController.tableView.reloadData()
46− }
47− }
48−
49 // curreent Active which can be displayed
13 // curreent Active which can be displayed
50− var currentActiveDialogs: [Model.Dialog] = [] {
14+ var currentActiveDialogs: [(id: Int, name: String)] = [(id: Int, name: String)]()
51− didSet {
52− tableView.reloadData()
53− }
54− }
55−
56− func setUpSearchContr(){
57−
58− searchController?.delegate = self
59− searchController?.obscuresBackgroundDuringPresentation = true
60− navigationItem.searchController = searchController
61− definesPresentationContext = true
62− searchController?.searchResultsUpdater = self
63− searchController?.searchBar.placeholder = "Search dialogs"
64−
65− }
66−
67− // curreent users
68− var users: [Int: Model.Users] = [:]
69
15
70 var onUserDisplayList: (()->())?
16 var onUserDisplayList: (()->())?
71
17
72− var onDialogDisplay: (((dialog: Model.Dialog, users: [Int:Model.Users]))->())?
18+ var onDialogDisplay: (((id: Int, name: String))->())?
73
19
74− var searchController: UISearchController?
20+ let searchC = UISearchController(searchResultsController: nil)
75
21
76 override func viewDidLoad() {
22 override func viewDidLoad() {
77 super.viewDidLoad()
23 super.viewDidLoad()
78−
24+
79− let updater = SuggestedDialogsTableViewController()
80−
81− updater.delegate = self
82− searchController = UISearchController(searchResultsController: updater)
83−
84 // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
25 // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
85 self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Write", style: .plain, target: self, action: #selector(choosePerson))
26 self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Write", style: .plain, target: self, action: #selector(choosePerson))
86
27
87 self.navigationItem.title = "Messages"
28 self.navigationItem.title = "Messages"
88 // self.navigationItem.largeTitleDisplayMode = .always
29 // self.navigationItem.largeTitleDisplayMode = .always
89− setUpSearchContr()
30+ self.navigationItem.searchController = searchC
90 navigationController?.navigationBar.prefersLargeTitles = true
31 navigationController?.navigationBar.prefersLargeTitles = true
91 self.navigationItem.hidesSearchBarWhenScrolling = false
32 self.navigationItem.hidesSearchBarWhenScrolling = false
92 }
33 }
@@ -97,14 +38,11 @@ class MessagesViewController: UITableViewController, UISearchControllerDelegate,
97
38
98 override func viewWillAppear(_ animated: Bool) {
39 override func viewWillAppear(_ animated: Bool) {
99 super.viewWillAppear(animated)
40 super.viewWillAppear(animated)
100− tabBarController?.tabBar.isHidden = false
41+
101− Model.getChatAll { [weak self] in
42+ tableView.reloadData()
102− self?.currentActiveDialogs = $0.0
103− self?.users = $0.1
104− }
105 }
43 }
106−
107 // MARK: - Table view data source
44 // MARK: - Table view data source
45+
108 override func numberOfSections(in tableView: UITableView) -> Int {
46 override func numberOfSections(in tableView: UITableView) -> Int {
109 return 1
47 return 1
110 }
48 }
@@ -116,66 +54,60 @@ class MessagesViewController: UITableViewController, UISearchControllerDelegate,
116
54
117 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
55 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
118 {
56 {
119− let cell = tableView.dequeueReusableCell(withIdentifier: "MessageViewCell", for: indexPath) as! MessageViewCell
57+ let cell = tableView.dequeueReusableCell(withIdentifier: "MessagesCell", for: indexPath)
120−
121− switch currentActiveDialogs[indexPath.row].self {
122− case .groupChat:
123− cell.fill(with: currentActiveDialogs[indexPath.row])
124− case .userChat(let userChat):
125− cell.fill(with: currentActiveDialogs[indexPath.row], user: users[userChat.user])
126− }
127
58
59+ cell.textLabel?.text = currentActiveDialogs[indexPath.row].name
60+ cell.detailTextLabel?.text = "from \(currentActiveDialogs[indexPath.row].name) some message is displayed here..."
61+
128 return cell
62 return cell
129 }
63 }
130
64
131 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
65 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
132− let tuple = (currentActiveDialogs[indexPath.row],users)
66+ onDialogDisplay?(currentActiveDialogs[indexPath.row])
133− onDialogDisplay?(tuple)
134 }
67 }
68+ /*
69+ // Override to support conditional editing of the table view.
70+ override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
71+ // Return false if you do not want the specified item to be editable.
72+ return true
135−}
73+ }
74+ */
136
75
76+ /*
77+ // Override to support editing the table view.
78+ override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
79+ if editingStyle == .delete {
80+ // Delete the row from the data source
81+ tableView.deleteRows(at: [indexPath], with: .fade)
82+ } else if editingStyle == .insert {
83+ // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
84+ }
85+ }
86+ */
87+
88+ /*
89+ // Override to support rearranging the table view.
90+ override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
137
91
138−class SuggestedDialogsTableViewController: UITableViewController {
139−
140− var idCell = "cell"
141−
142− var users: [Int: Model.Users] = [:]
143−
144− weak var delegate: SelectableDialog?
145−
146− var currentDialogs: [Model.Dialog] = []
147−
148− override func viewDidLoad() {
149− super.viewDidLoad()
150− tableView.register(UITableViewCell.self, forCellReuseIdentifier: idCell)
151− tableView.reloadData()
152− }
153−
154− override func numberOfSections(in tableView: UITableView) -> Int {
155− return 1
156− }
157−
158− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
159− return currentDialogs.count
160 }
92 }
161−
93+ */
94+
95+ /*
96+ // Override to support conditional rearranging of the table view.
162− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
97+ override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
163− {
98+ // Return false if you do not want the item to be re-orderable.
164− let cell = tableView.dequeueReusableCell(withIdentifier: idCell, for: indexPath)
165−
166− switch currentDialogs[indexPath.row] {
167− case .groupChat(let groupChat):
168− cell.textLabel?.text = groupChat.group.name
169− case .userChat(let userChat):
170− cell.textLabel?.text = users[userChat.user]?.fullName()
171− }
172−
173− cell.accessoryType = .disclosureIndicator
174− return cell
99+ return true
175 }
100 }
176−
101+ */
177− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
102+
178− delegate?.openDialog(with: currentDialogs[indexPath.row])
103+ /*
179− // self.dismiss(animated: true)
104+ // MARK: - Navigation
105+
106+ // In a storyboard-based application, you will often want to do a little preparation before navigation
107+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
108+ // Get the new view controller using segue.destination.
109+ // Pass the selected object to the new view controller.
180 }
110 }
111+ */
112+
181}
113}
GDproject/Controller/Messages/PeopleToWriteViewController.swift+61−22
@@ -10,58 +10,97 @@ import UIKit
10
10
11class PeopleToWriteViewController: UITableViewController {
11class PeopleToWriteViewController: UITableViewController {
12
12
13− // TODO: - edit button when it's used for selection
14− var whatToDoWithSelection: (([Int: Model.UserPermission])->())?
15−
16 let searchC = UISearchController(searchResultsController: nil)
13 let searchC = UISearchController(searchResultsController: nil)
17
14
18− let users = Model.Channels.fullPeople
15+ let users = [(id: 9,name: "Anna Mikhaleva")]
19−
20− var chosenUsers: [Int: Model.UserPermission] = [:]
21
16
22 override func viewDidLoad() {
17 override func viewDidLoad() {
23 super.viewDidLoad()
18 super.viewDidLoad()
24
19
25− tableView.isEditing = true
26 self.navigationItem.title = "People"
20 self.navigationItem.title = "People"
27−
28− self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(newMessage))
29−
30 self.navigationItem.largeTitleDisplayMode = .never
21 self.navigationItem.largeTitleDisplayMode = .never
31 self.navigationItem.searchController = searchC
22 self.navigationItem.searchController = searchC
32 self.navigationItem.hidesSearchBarWhenScrolling = false
23 self.navigationItem.hidesSearchBarWhenScrolling = false
33 }
24 }
34
25
35− override func setEditing(_ editing: Bool, animated: Bool) {
26+ // MARK: - Table view data source
36− super.setEditing(true, animated: animated)
37− }
38
27
39 override func numberOfSections(in tableView: UITableView) -> Int {
28 override func numberOfSections(in tableView: UITableView) -> Int {
29+ // #warning Incomplete implementation, return the number of sections
40 return 1
30 return 1
41 }
31 }
42
32
43 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
33 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
34+ // #warning Incomplete implementation, return the number of rows
44 return users.count
35 return users.count
45 }
36 }
46
37
47− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
48− chosenUsers[users[indexPath.row].id] = Model.UserPermission(isAdmin: false)
49− }
50
38
51 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
39 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
52 {
40 {
53 let cell = tableView.dequeueReusableCell(withIdentifier: "peopleToWriteCell", for: indexPath)
41 let cell = tableView.dequeueReusableCell(withIdentifier: "peopleToWriteCell", for: indexPath)
54
42
55− cell.textLabel?.text = users[indexPath.row].fullName()
43+ cell.textLabel?.text = users[indexPath.row].name
44+ cell.detailTextLabel?.text = "\(users[indexPath.row].id)"
56
45
57 return cell
46 return cell
58 }
47 }
59−
48+
60− @objc func newMessage()
49+ override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
61− {
50+ navigationController?.popViewController(animated: true)
62− if chosenUsers.count != 0
51+
52+ guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else
63 {
53 {
64− whatToDoWithSelection?(chosenUsers)
54+ (navigationController?.viewControllers.last as? MessagesViewController)?.currentActiveDialogs.append(users[indexPath.row])
55+ (navigationController?.viewControllers.last as? MessagesViewController)?.onDialogDisplay?(users[indexPath.row])
56+ return
65 }
57 }
66 }
58 }
59+
60+
61+ /*
62+ // Override to support conditional editing of the table view.
63+ override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
64+ // Return false if you do not want the specified item to be editable.
65+ return true
66+ }
67+ */
68+
69+ /*
70+ // Override to support editing the table view.
71+ override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
72+ if editingStyle == .delete {
73+ // Delete the row from the data source
74+ tableView.deleteRows(at: [indexPath], with: .fade)
75+ } else if editingStyle == .insert {
76+ // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
77+ }
78+ }
79+ */
80+
81+ /*
82+ // Override to support rearranging the table view.
83+ override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
84+
85+ }
86+ */
87+
88+ /*
89+ // Override to support conditional rearranging of the table view.
90+ override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
91+ // Return false if you do not want the item to be re-orderable.
92+ return true
93+ }
94+ */
95+
96+ /*
97+ // MARK: - Navigation
98+
99+ // In a storyboard-based application, you will often want to do a little preparation before navigation
100+ override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
101+ // Get the new view controller using segue.destination.
102+ // Pass the selected object to the new view controller.
103+ }
104+ */
105+
67}
106}
GDproject/Controller/Profile/BasicInfoController.swift+11−16
@@ -16,20 +16,17 @@ struct CellData{
16
16
17class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
17class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
18
18
19− var userInfo: Model.Users? {
19+ var dataSourse: [CellData] = [
20− didSet {
20+ CellData(opened: false, title: "Phone", sectionData: ["+7 901 733 01 79"]),
21− if let userInfo = userInfo {
22− dataSourse = [CellData(opened: false, title: "Contacts", sectionData: [userInfo.email, userInfo.faculty.address]),
21+ CellData(opened: false, title: "Mail", sectionData: ["vbogomazova@edu.hse.ru"]),
23− CellData(opened: false, title: "Faculty", sectionData: [userInfo.faculty.campusName, userInfo.faculty.name, userInfo.faculty.address, userInfo.faculty.path]),
22+ CellData(opened: false, title: "Research ID", sectionData: ["4567834336789456737"]),
23+ CellData(opened: false, title: "Published", sectionData: ["Это будет очень длинное название книги 1, чтобы сделать проверку", "Книга 2", "Книга 3"]),
24− CellData(opened: false, title: "Interests", sectionData: userInfo.faculty.tags)]
24+ CellData(opened: false, title: "Courses", sectionData: ["Курс 1", "Курс 2"]),
25− }
25+ CellData(opened: false, title: "Link", sectionData: ["https://wwww.hse.ru"])
26− }
26+ ]
27− }
28−
29− var dataSourse: [CellData] = [ ]
30
27
31 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
28 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
32− if (dataSourse[section].opened) {
29+ if (dataSourse[section].opened){
33 return dataSourse[section].sectionData.count + 1
30 return dataSourse[section].sectionData.count + 1
34 } else {
31 } else {
35 return 1
32 return 1
@@ -48,10 +45,8 @@ class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDat
48 cell.selectionStyle = .none
45 cell.selectionStyle = .none
49 return cell
46 return cell
50 } else {
47 } else {
51− let cell = tableView.dequeueReusableCell(withIdentifier: infoCellId, for: indexPath) as! InfoCell
48+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
52− cell.fill(title: dataSourse[indexPath.section].sectionData[indexPath.row - 1])
49+ cell.textLabel?.text = dataSourse[indexPath.section].sectionData[indexPath.row - 1]
53− cell.accessoryType = .none
54− cell.selectionStyle = .none
55 return cell
50 return cell
56 }
51 }
57 }
52 }
GDproject/Controller/Profile/InfoCell.swift+1−2
@@ -16,9 +16,8 @@ class InfoCell: UITableViewCell{
16 label.font = UIFont.systemFont(ofSize: 16)
16 label.font = UIFont.systemFont(ofSize: 16)
17 label.sizeToFit()
17 label.sizeToFit()
18 label.isScrollEnabled = false
18 label.isScrollEnabled = false
19− // label.isUserInteractionEnabled = false
19+ label.isUserInteractionEnabled = false
20 label.isEditable = false
20 label.isEditable = false
21− label.dataDetectorTypes = .all
22 label.textColor = .black
21 label.textColor = .black
23 return label
22 return label
24 }()
23 }()
GDproject/Controller/Profile/ProfileViewController.swift+55−139
@@ -9,17 +9,8 @@
9import UIKit
9import UIKit
10import TinyConstraints
10import TinyConstraints
11
11
12−protocol UpdateUser: class {
13− func updateUserObj(with user: Model.Users)
14−}
15−
16−class ProfileViewController: UIViewController, UpdateUser
12+class ProfileViewController: UIViewController
17{
13{
18− func updateUserObj(with user: Model.Users)
19− {
20− self.user = user
21− Model.Channels.fullPeopleDict[user.id] = user
22− }
23
14
24 @IBOutlet weak var segmentedControl: UISegmentedControl!
15 @IBOutlet weak var segmentedControl: UISegmentedControl!
25
16
@@ -41,31 +32,18 @@ class ProfileViewController: UIViewController, UpdateUser
41
32
42 var logOut: (()->())?
33 var logOut: (()->())?
43
34
44− var deleteAllSessions: (()->())?
45−
46 var onSettings: (()->())?
35 var onSettings: (()->())?
47
36
48− @IBAction func sendMessage(_ sender: UIButton)
37+ var onChannelsListToAddAPerson: ((Model.Users)->())?
49− {
50− if let userId = idProfile
51− {
52− let createdDialog = Model.Dialog.userChat(Model.UserChat(user: userId))
53− let vc = DialogViewController()
54− vc.users = Model.Channels.fullPeopleDict
55− vc.dialog = createdDialog
56− self.navigationController?.pushViewController(vc, animated: true)
57− }
58− }
59
38
60− var protoDictionary: [String: UIImage] = ["135213": #imageLiteral(resourceName: "9"), "135288": #imageLiteral(resourceName: "5051"), "22723" : #imageLiteral(resourceName: "69"), "135083": #imageLiteral(resourceName: "42")]
39+ var protoDictionary: [Int: UIImage] = [9: #imageLiteral(resourceName: "9"), 5051: #imageLiteral(resourceName: "5051"), 69: #imageLiteral(resourceName: "69"), 42: #imageLiteral(resourceName: "42")]
61
40
62− func fill(with user: Model.Users)
41+ func fill(with user: Model.Users){
63− {
42+ self.facultyLabel.text = "Студент: Факультет Компьютерных Наук"
64− self.facultyLabel.text = user.faculty.name
65 self.nameLabel.text = "\(user.firstName) \(user.middleName)"
43 self.nameLabel.text = "\(user.firstName) \(user.middleName)"
66 self.surnameLabel.text = "\(user.lastName)"
44 self.surnameLabel.text = "\(user.lastName)"
67− self.profileImageView.image = protoDictionary[user.faculty.campusCode]?.roundedImage
45+ self.profileImageView.image = protoDictionary[user.id]?.roundedImage
68− self.placeLabel.text = "📍\(user.faculty.address)"
46+ self.placeLabel.text = "📍Москва, Кочновский пр.3"
69 if user.id == DataStorage.standard.getUserId() {
47 if user.id == DataStorage.standard.getUserId() {
70 newMessageButton.isHidden = true
48 newMessageButton.isHidden = true
71 } else {
49 } else {
@@ -75,61 +53,44 @@ class ProfileViewController: UIViewController, UpdateUser
75
53
76 var user: Model.Users? {
54 var user: Model.Users? {
77 didSet {
55 didSet {
78− if let user = user {
79− self.fill(with: user)
56+ self.fill(with: user!)
80− navigationItem.title = "\(user.firstName) \(user.lastName)"
57+ Model.getPostsForUser(with: user!.id) { [weak self] (posts) in
81− } else if let id = idProfile {
58+ self?.dataSourse = posts
82− Model.getUsers(for: [id]) { [unowned self ] in
83− self.user = $0[id]
84− }
85 }
59 }
60+ navigationItem.title = "\(user!.firstName) \(user!.lastName)"
86 }
61 }
87 }
62 }
88
63
89− var channel: Model.Channels? {
64+ var basicInfo = BasicInfoController()
90− didSet {
65+ var posts = NewsVC()
91− self.update()
92− }
93− }
94
66
95− func update()
67+ var dataSourse: [Model.Posts]?{
96− {
68+ didSet{
97− Model.getAnonymousChannel(by: channel!) { [unowned self] in
69+
98− self.posts.dataSourse = $0.posts
70+ var newPosts: [Model.Posts] = []
99− self.posts.dictionary = $0.users
71+
100− self.user = $0.users[self.idProfile!]
72+ dataSourse?.forEach({ (post) in
73+ newPosts.append(Model.Posts(body: post.body, authorId: post.authorId, id: post.id, user: user!, date: post.updated, tags: post.tags))
74+ })
75+
76+ self.posts.dataSourse = newPosts
77+ tableView.reloadData()
101 }
78 }
102 }
79 }
103
80
104− var basicInfo = BasicInfoController()
105− var posts = NewsVC()
106−
107 override func viewDidLoad()
81 override func viewDidLoad()
108 {
82 {
109 super.viewDidLoad()
83 super.viewDidLoad()
110− if idProfile == nil {
84+ print("hell")
111− idProfile = DataStorage.standard.getUserId()
112− }
113−
114 posts.viewController = self
85 posts.viewController = self
115 posts.type = .NONE
86 posts.type = .NONE
116− posts.currChannel = channel
117−
118− posts.onFullPost = {
119− [weak self] (type,post) in
120−
121− let vc = self?.storyboard?.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
122− vc.type = type
123− vc.post = post
124− self?.navigationController!.pushViewController(vc, animated: true)
125− }
126
87
127 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
88 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
128
89
129 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
90 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
130
91
131 tableView.register(BasicInfoCell.self, forCellReuseIdentifier: basicInfoCellId)
92 tableView.register(BasicInfoCell.self, forCellReuseIdentifier: basicInfoCellId)
132−
93+
133 tableView.register(InfoCell.self, forCellReuseIdentifier: infoCellId)
94 tableView.register(InfoCell.self, forCellReuseIdentifier: infoCellId)
134
95
135 posts.viewController = self
96 posts.viewController = self
@@ -139,27 +100,29 @@ class ProfileViewController: UIViewController, UpdateUser
139 tableView.reloadData()
100 tableView.reloadData()
140 }
101 }
141
102
142− var idProfile: Int? {
103+ var idProfile: Int?
143− didSet {
144− channel = Model.Channels(people: [idProfile!], name: "", id: 0, tags: [])
145− }
146− }
147
104
148 override func viewWillAppear(_ animated: Bool) {
105 override func viewWillAppear(_ animated: Bool) {
149− tabBarController?.tabBar.isHidden = false
150
106
151 if idProfile == nil {
107 if idProfile == nil {
152 idProfile = DataStorage.standard.getUserId()
108 idProfile = DataStorage.standard.getUserId()
153 }
109 }
154− user = Model.Channels.fullPeopleDict[idProfile!]
155
110
156− update()
111+ if let id = idProfile {
112+ if let user = Model.idUser[id] {
113+ self.user = user
114+ } else {
115+ Model.getUsers(for: [id]) { [weak self] (dic) in
116+ self?.user = dic[id]
117+ }
118+ }
119+ }
157
120
158 setUpNavigarionBar()
121 setUpNavigarionBar()
159 }
122 }
160
123
161 func setUpNavigarionBar(){
124 func setUpNavigarionBar(){
162− // navigationController?.navigationBar.prefersLargeTitles = true
125+ navigationController?.navigationBar.prefersLargeTitles = true
163 let uibarbutton = UIBarButtonItem(title: "More", style: .plain, target: self, action: #selector(showInformation))
126 let uibarbutton = UIBarButtonItem(title: "More", style: .plain, target: self, action: #selector(showInformation))
164 navigationItem.rightBarButtonItems = [uibarbutton]
127 navigationItem.rightBarButtonItems = [uibarbutton]
165 navigationItem.largeTitleDisplayMode = .always
128 navigationItem.largeTitleDisplayMode = .always
@@ -169,75 +132,29 @@ class ProfileViewController: UIViewController, UpdateUser
169
132
170 let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
133 let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
171
134
172−
173− let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
135+ let channelAction = UIAlertAction(title: "Add to a channel", style: .default){
136+ [weak self] (_) in
137+ self?.onChannelsListToAddAPerson?(self!.user!)
138+ }
174
139
140+ let settingsAction = UIAlertAction(title: "Setting", style: .default)
141+ { [weak self] (_) in
142+ self?.onSettings?()
143+ }
175
144
176− if idProfile == DataStorage.standard.getUserId() {
145+ let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
146+
177− let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
147+ let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
178− { [weak self] (_) in
148+ { [weak self]
179−
180− if let logOut = self?.logOut {
181− logOut()
182− } else {
183− Model.logout() {
184− DataStorage.standard.setIsLoggedIn(value: false, with: 0)
185− (UIApplication.shared.delegate as! AppDelegate).relaunch()
186− }
187− }
188− }
189−
190− let deleetAllSessionsAction = UIAlertAction(title: "Delete all sessions", style: .destructive)
191− { [weak self] _ in
192−
193− if let delete = self?.deleteAllSessions {
194− delete()
195− } else {
196− Model.deactivateAll() {
197− DataStorage.standard.setIsLoggedIn(value: false, with: 0)
198− (UIApplication.shared.delegate as! AppDelegate).relaunch()
199− }
200− }
201− }
202−
203− let settingsAction = UIAlertAction(title: "Edit profile", style: .default)
204− { [weak self] (_) in
149+ (_) in
205−
150+ self?.logOut?()
206− if let settings = self?.onSettings{
207− settings()
208− } else {
209− let vc = self?.storyboard?.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
210− vc.delegate = self
211− vc.userActive = self?.user
212−
213− self?.navigationController?.pushViewController(vc, animated: true)
214− }
215− }
216−
217− optionMenu.addAction(settingsAction)
218− optionMenu.addAction(logoutAction)
219− optionMenu.addAction(deleetAllSessionsAction)
220− } else {
221− let channelAction = UIAlertAction(title: "Add to a channel", style: .default)
222− {
223− [weak self] (_) in
224−
225− let vc = self?.storyboard?.instantiateViewController(withIdentifier: simplifiedChannelsList) as! SimplifiedChannelsList
226− vc.user = self?.user
227−
228− let transition = CATransition()
229− transition.duration = 0.5
230− transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
231− transition.type = CATransitionType.moveIn
232− transition.subtype = CATransitionSubtype.fromTop
233− self?.navigationController?.view.layer.add(transition, forKey: nil)
234− self?.navigationController?.pushViewController(vc, animated: false)
235− }
236−
237− optionMenu.addAction(channelAction)
238 }
151 }
239
152
153+ optionMenu.addAction(channelAction)
154+ optionMenu.addAction(settingsAction)
155+ optionMenu.addAction(logoutAction)
240 optionMenu.addAction(cancelAction)
156 optionMenu.addAction(cancelAction)
157+
241 self.present(optionMenu, animated: true, completion: nil)
158 self.present(optionMenu, animated: true, completion: nil)
242 }
159 }
243
160
@@ -267,7 +184,6 @@ class ProfileViewController: UIViewController, UpdateUser
267 func changeToBasicInfo(){
184 func changeToBasicInfo(){
268 tableView.delegate = basicInfo
185 tableView.delegate = basicInfo
269 tableView.dataSource = basicInfo
186 tableView.dataSource = basicInfo
270− basicInfo.userInfo = self.user
271 tableView.reloadData()
187 tableView.reloadData()
272 }
188 }
273}
189}
GDproject/DataStorage.swift−8
@@ -37,13 +37,6 @@ class DataStorage{
37 return UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
37 return UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
38 }
38 }
39
39
40− func setEmail(email: String) {
41− UserDefaults.standard.set(email, forKey: UserDefaultsKeys.email.rawValue)
42− }
43−
44− func getEmail() -> String? {
45− return UserDefaults.standard.string(forKey: UserDefaultsKeys.email.rawValue)
46− }
47 /**
40 /**
48 Function to determine is user logged in already or not
41 Function to determine is user logged in already or not
49 */
42 */
@@ -56,5 +49,4 @@ class DataStorage{
56enum UserDefaultsKeys: String{
49enum UserDefaultsKeys: String{
57 case loggedIn
50 case loggedIn
58 case id
51 case id
59− case email
60}
52}
GDproject/Extentions.swift−47
@@ -60,50 +60,3 @@ extension UIStoryboard {
60 return UIStoryboard.userEdit.instantiateViewController(withIdentifier: logInController) as! LogInViewController
60 return UIStoryboard.userEdit.instantiateViewController(withIdentifier: logInController) as! LogInViewController
61 }
61 }
62}
62}
63−
64−
65−extension String {
66− func getDate() -> String
67− {
68− let dateFormatter = DateFormatter()
69− dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"//this your string date format
70− dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
71− let date = dateFormatter.date(from: self)
72−
73− dateFormatter.dateFormat = "MMM d, yyyy HH:mm" ///this is what you want to convert format
74− dateFormatter.timeZone = NSTimeZone.local
75− let timeStamp = dateFormatter.string(from: date!)
76−
77− return timeStamp
78− }
79−}
80−
81−extension UIViewController {
82− func showAlertOn(result: ResultR) {
83−
84− let message: String
85−
86− switch result {
87− case .impossibleContent:
88− message = "Impossible content"
89− case .exceededContent:
90− message = "The content exceeded"
91− case .longContent:
92− message = "The content is too long"
93− case .badAccess:
94− message = "Try reloading the page again"
95− case .alreadyRegistered:
96− message = "User is already registered"
97− case .tooMuchToAdd:
98− message = "Limit of channels exceeded"
99− case .success, .success1:
100− return
101− default:
102− message = "Something went wrong"
103− }
104−
105− let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
106− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
107− self.present(alert, animated: true, completion: nil)
108− }
109−}
GDproject/Simple model/CompletionTree.swift+1−2
@@ -27,8 +27,7 @@ struct CompletionTree: Codable {
27 }
27 }
28 }
28 }
29
29
30− static func getValues(tree: CompletionTree) -> [String]
30+ static func getValues(tree: CompletionTree) -> [String] {
31− {
32 var out = [String]()
31 var out = [String]()
33
32
34 if let treeVal = tree.value {
33 if let treeVal = tree.value {
GDproject/Simple model/Model.swift+40−651
@@ -10,56 +10,29 @@ import Foundation
10import UIKit
10import UIKit
11import Alamofire
11import Alamofire
12
12
13−enum ResultR: Int {
14− case internalServerError = 500
15− case exceededContent = 470
16− case longContent = 471
17− case incorrectContent = 472
18− case impossibleContent = 473
19− case invalidTocken = 498
20− case alreadyRegistered = 409
21− case invalidCode = 403
22− case badAccess = 400
23− case tooMuchToAdd = 406
24− case notFound = 404
25− case success1 = 204
26− case success = 200
27−}
28−
29class Model{
13class Model{
30
14
31 static let invalidTocken = 498
15 static let invalidTocken = 498
32
16
33− static var hashTagTree: CompletionTree?
17+ static var hashTagTree: CompletionTree?
34
18
35 private static var isValidTocken: ((Int)->())? = { responce in
19 private static var isValidTocken: ((Int)->())? = { responce in
36 print(responce)
20 print(responce)
37 if responce == invalidTocken {
21 if responce == invalidTocken {
38−
39 DataStorage.standard.setIsLoggedIn(value: false, with: 0)
22 DataStorage.standard.setIsLoggedIn(value: false, with: 0)
40 (UIApplication.shared.delegate as! AppDelegate).relaunch()
23 (UIApplication.shared.delegate as! AppDelegate).relaunch()
41−
42− Model.logout {
43− print("Logout Is Successful")
44− }
45 }
24 }
46 }
25 }
47
26
48 private static let baseUrl = "https://valera-denis.herokuapp.com"
27 private static let baseUrl = "https://valera-denis.herokuapp.com"
49 static let decoder = JSONDecoder()
28 static let decoder = JSONDecoder()
50−
29+
51− static let authMeURL = URL(string: "\(baseUrl)/authentication/me")!
52− static let deactivateURL = URL(string: "\(baseUrl)/deactivateAll")!
53− static let registerMeURL = URL(string: "\(baseUrl)/authentication/register")!
54− static let authVerifyURL = URL(string: "\(baseUrl)/authentication/verify")!
55 static let authenticationURL = URL(string:"\(baseUrl)/authentication/login")!
30 static let authenticationURL = URL(string:"\(baseUrl)/authentication/login")!
56− static let logOutURL = URL(string:"\(baseUrl)/authentication/logout")!
57 static let postsLastURL = URL(string:"\(baseUrl)/posts/last")!
31 static let postsLastURL = URL(string:"\(baseUrl)/posts/last")!
58 static let postsForUserURL = URL(string:"\(baseUrl)/posts/forUser")!
32 static let postsForUserURL = URL(string:"\(baseUrl)/posts/forUser")!
59 static let postsPublishURL = URL(string:"\(baseUrl)/posts/publish")!
33 static let postsPublishURL = URL(string:"\(baseUrl)/posts/publish")!
60 static let usersURL = URL(string:"\(baseUrl)/users")!
34 static let usersURL = URL(string:"\(baseUrl)/users")!
61 static let usersAllURL = URL(string:"\(baseUrl)/users/all")!
35 static let usersAllURL = URL(string:"\(baseUrl)/users/all")!
62− static let usersUpdateURL = URL(string:"\(baseUrl)/users/update")!
63 static let channelsGetURL = URL(string: "\(baseUrl)/channels/get")!
36 static let channelsGetURL = URL(string: "\(baseUrl)/channels/get")!
64 static let channelsUpdateURL = URL(string: "\(baseUrl)/channels/update")!
37 static let channelsUpdateURL = URL(string: "\(baseUrl)/channels/update")!
65 static let channelsListURL = URL(string: "\(baseUrl)/channels")!
38 static let channelsListURL = URL(string: "\(baseUrl)/channels")!
@@ -67,21 +40,11 @@ class Model{
67 static let channelsDeleteURL = URL(string: "\(baseUrl)/channels/delete")!
40 static let channelsDeleteURL = URL(string: "\(baseUrl)/channels/delete")!
68 static let channelsGetAnonURL = URL(string: "\(baseUrl)/channels/getAnonymous")!
41 static let channelsGetAnonURL = URL(string: "\(baseUrl)/channels/getAnonymous")!
69 static let complexURL = URL(string: "\(baseUrl)/complex")!
42 static let complexURL = URL(string: "\(baseUrl)/complex")!
70− static let hashTagTreeURL = URL(string: "\(baseUrl)/tags/completions")!
43+ static let hashTagTreeURL = URL(string: "\(baseUrl)/tagCompletions")!
71− static let createGroupChatURL = URL(string: "\(baseUrl)/chats/createGroupChat")!
72− static let chatsGetAllURL = URL(string: "\(baseUrl)/chats/getAll")!
73− static let getGroupChatURL = URL(string: "\(baseUrl)/chats/getGroupChat")!
74− static let leaveGroupChatURL = URL(string: "\(baseUrl)/chats/leaveGroupChat")!
75− static let updateGroupChatURL = URL(string: "\(baseUrl)/chats/updateGroupChat")!
76− static let messagesGetGroupChatURL = URL(string: "\(baseUrl)/messages/get/groupChat")! //r
77− static let messagesSendURL = URL(string: "\(baseUrl)/messages/send")!
78− static let messagesGetUserChatURL = URL(string: "\(baseUrl)/messages/get/userChat")!
79− static let facultySearchURL = URL(string: "\(baseUrl)/faculty/search")!
80−
81
44
82− struct QueryPosts<T: Codable>: Codable {
45+ struct QueryPosts: Codable {
83 var users: [Int: Users]
46 var users: [Int: Users]
84− var response: [T]
47+ var response: [Posts]
85 }
48 }
86
49
87 struct Posts: Codable {
50 struct Posts: Codable {
@@ -148,8 +111,6 @@ class Model{
148 var lastName: String
111 var lastName: String
149 var firstName: String
112 var firstName: String
150 var id: Int
113 var id: Int
151− var faculty: Faculty
152− var email: String
153
114
154 func fullName() -> String {
115 func fullName() -> String {
155 return "\(firstName) \(lastName)"
116 return "\(firstName) \(lastName)"
@@ -213,108 +174,24 @@ class Model{
213 }
174 }
214 }
175 }
215
176
216− struct AuthStatus: Codable {
217− var userStatus: String
218−
219− init(){
220− userStatus = "invalid"
221− }
222− }
223−
224− static func logout(completion: @escaping (()->())){
177+ static func authenticate(with id: Int, completion: @escaping ((Bool)->())) {
225− var request = URLRequest(url: logOutURL)
226− request.httpMethod = "POST"
227
178
228− AF.request(request).response { (responce) in
179+ let json: [String:Any] = ["authenticationId" : id]
229− isValidTocken?(responce.response?.statusCode ?? 498)
180+ let jsonData = try? JSONSerialization.data(withJSONObject: json)
230−
231− if let code = responce.response?.statusCode, code == 498 {
232− return
233− }
234−
235− completion()
236− }
237− }
238−
239− /*
240− "email": "vchernyshev@hse.ru",
241− "middleName": "Algebrovich",
242− "lastName": "Leonidov",
243− "faculty": "cs.hse.ru/dse",
244− "firstName": "Seva"
245− */
246−
247− struct NewRegistration: Codable{
248− var email: String
249− var firstName: String?
250− var middleName: String?
251− var lastName: String?
252− var faculty: String?
253− }
254−
255− static func register(object: NewRegistration, completion: @escaping (()->())) {
256− var request = URLRequest(url: registerMeURL)
257− request.httpBody = try? JSONEncoder().encode(object)
258
181
182+ var request = URLRequest(url: authenticationURL)
259 request.httpMethod = "POST"
183 request.httpMethod = "POST"
260− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
261
184
262− AF.request(request).response { (responce) in
185+ // insert json data to the request
263−
264− guard let code = responce.response?.statusCode else { return }
265− isValidTocken?(code)
266−
267− if let code = responce.response?.statusCode, code == 498 {
268− return
269− }
270−
271− if code == 204 {
272−
273− let fields = responce.response?.allHeaderFields as? [String :String]
274− let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields!, for: responce.response!.url!)
275− HTTPCookieStorage.shared.setCookie(cookies[0])
276−
277− completion()
278− }
279− }
280− }
281−
282− // true only if everything is good
283− static func verify(with code: Int, completion: @escaping ((Bool)->())){
284− var request = URLRequest(url: authVerifyURL)
285− request.httpMethod = "POST"
286− request.httpBody = "\(code)".data(using: .utf8)
186+ request.httpBody = jsonData
287 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
187 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
288
188
289 AF.request(request).response { (responce) in
189 AF.request(request).response { (responce) in
290
190
291− guard let statusCode = responce.response?.statusCode else { completion(false); return }
191+ guard let realResponse = responce.response, realResponse.statusCode == 200 else
292− isValidTocken?(statusCode)
192+ {
293−
193+ print("Not a 200 response")
294− if let code = responce.response?.statusCode, code == 498 {
295− return
296− }
297−
298− if statusCode == 204 {
299− // at this point cookies are set
300− completion(true)
301− } else {
302 completion(false)
194 completion(false)
303− }
304− }
305− }
306−
307− // yes or no
308− static func authenticateMe(completion: @escaping ((Bool)->())){
309− var request = URLRequest(url: authMeURL)
310− request.httpMethod = "POST"
311−
312− AF.request(request).response { (responce) in
313−
314− guard let statusCode = responce.response?.statusCode else { completion(false); return }
315− isValidTocken?(statusCode)
316−
317− if let code = responce.response?.statusCode, code == 498 {
318 return
195 return
319 }
196 }
320
197
@@ -324,67 +201,26 @@ class Model{
324 return
201 return
325 }
202 }
326
203
327− DataStorage.standard.setIsLoggedIn(value: true, with: personId)
204+ let fields = realResponse.allHeaderFields as? [String :String]
328− completion(true)
329− }
330− }
331−
332− // register, ok or invalid
333− static func authenticate(with email: String, completion: @escaping ((AuthStatus)->())) {
334−
335− let json: [String:Any] = ["authenticationEmail" : email]
336− let jsonData = try? JSONSerialization.data(withJSONObject: json)
337−
338− var request = URLRequest(url: authenticationURL)
339− request.httpMethod = "POST"
340−
341− // insert json data to the request
342− request.httpBody = jsonData
343− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
344−
345− AF.request(request).response { (response) in
346
205
347− guard let realResponse = response.response, realResponse.statusCode == 200 else
206+ let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields!, for: realResponse.url!)
348− {
349− print("Not a 200 response")
350− completion(AuthStatus())
351− return
352− }
353−
354− guard let json = response.data else { return }
355− guard let res = try? decoder.decode(AuthStatus.self, from: json) else { return }
356
207
357− if realResponse.statusCode == 200 && res.userStatus == "registered"
358− {
359− // at this point cookies are set
360− let fields = realResponse.allHeaderFields as? [String :String]
361− let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields!, for: realResponse.url!)
362− HTTPCookieStorage.shared.setCookie(cookies[0])
208+ HTTPCookieStorage.shared.setCookie(cookies[0])
363− }
364
209
210+ DataStorage.standard.setIsLoggedIn(value: true, with: personId)
365− completion(res)
211+ completion(true)
366 }
212 }
367 }
213 }
368
214
369− struct GeneralRequest<T: Codable>: Codable
215+ struct PostsLastRequest<T: Codable>: Codable {
370− {
371− var direction: String
372 var limit: Int
216 var limit: Int
373 var exclusiveFrom: Int?
217 var exclusiveFrom: Int?
374 var request: T
218 var request: T
375
219
376− init(direction: String = "backward", limit: Int, exclusiveFrom: Int?, request: T) {
377− self.direction = direction
378− self.limit = limit
379− self.exclusiveFrom = exclusiveFrom
380− self.request = request
381− }
382−
383 enum CodingKeys: String, CodingKey {
220 enum CodingKeys: String, CodingKey {
384 case limit
221 case limit
385 case exclusiveFrom
222 case exclusiveFrom
386 case request
223 case request
387− case direction
388 }
224 }
389
225
390 func encode(to encoder: Encoder) throws {
226 func encode(to encoder: Encoder) throws {
@@ -392,13 +228,12 @@ class Model{
392 try container.encode(limit, forKey: .limit)
228 try container.encode(limit, forKey: .limit)
393 try container.encode(exclusiveFrom, forKey: .exclusiveFrom)
229 try container.encode(exclusiveFrom, forKey: .exclusiveFrom)
394 try container.encode(request, forKey: .request)
230 try container.encode(request, forKey: .request)
395− try container.encode(direction, forKey: .direction)
396 }
231 }
397 }
232 }
398
233
399 static func getLast(on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
234 static func getLast(on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
400 {
235 {
401− let postRequest = GeneralRequest<[Int]>(limit: limit, exclusiveFrom: pointInTime, request: [])
236+ let postRequest = PostsLastRequest<[Int]>(limit: limit, exclusiveFrom: pointInTime, request: [])
402
237
403 var request = URLRequest(url: postsLastURL)
238 var request = URLRequest(url: postsLastURL)
404 request.httpBody = try? JSONEncoder().encode(postRequest)
239 request.httpBody = try? JSONEncoder().encode(postRequest)
@@ -412,13 +247,9 @@ class Model{
412
247
413 isValidTocken?(response.response?.statusCode ?? 498)
248 isValidTocken?(response.response?.statusCode ?? 498)
414
249
415− if let code = response.response?.statusCode, code == 498 {
416− return
417− }
418−
419 guard let json = response.data else { return }
250 guard let json = response.data else { return }
420
251
421− guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { print("no")
252+ guard let newQueery = try? decoder.decode(QueryPosts.self, from: json) else { print("no")
422 return }
253 return }
423
254
424 idUser = newQueery.users
255 idUser = newQueery.users
@@ -427,7 +258,7 @@ class Model{
427 }
258 }
428
259
429
260
430− static func createAndPublish(body: [Attachments], tags: [String], completion: @escaping ((ResultR)->())){
261+ static func createAndPublish(body: [Attachments], tags: [String]){
431 let jsonUpd = CreatedPost(body: body, tags: tags)
262 let jsonUpd = CreatedPost(body: body, tags: tags)
432 var request = URLRequest(url: postsPublishURL)
263 var request = URLRequest(url: postsPublishURL)
433
264
@@ -441,30 +272,17 @@ class Model{
441 (response) in
272 (response) in
442
273
443 isValidTocken?(response.response?.statusCode ?? 498)
274 isValidTocken?(response.response?.statusCode ?? 498)
444−
445− if let code = response.response?.statusCode, code == 498 {
446− return
447− }
448−
449− if let code = response.response?.statusCode,
450− let result = ResultR(rawValue: code)
451− {
452− completion(result)
453− } else {
454− completion(.internalServerError)
455− }
456 }
275 }
457 }
276 }
458
277
459−// static func requestForPosts(limit: Int = 10, ){
460−//
461−// }
462
278
463− static func getPostsForUser(for limit: Int = 10, from pointInTime: Int? = nil, with id: Int, completion: @escaping (([Posts])->()))
279+ static func getPostsForUser(with id: Int, completion: @escaping (([Posts])->())){
464− {
280+ let json = [
465− let postsRequest = GeneralRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: id)
281+ "request" : id,
282+ "limit": 10
283+ ]
466
284
467− let jsonData = try? JSONEncoder().encode(postsRequest)
285+ let jsonData = try? JSONSerialization.data(withJSONObject: json)
468
286
469 var request = URLRequest(url: postsForUserURL)
287 var request = URLRequest(url: postsForUserURL)
470 request.httpMethod = "POST"
288 request.httpMethod = "POST"
@@ -478,13 +296,9 @@ class Model{
478
296
479 isValidTocken?(response.response?.statusCode ?? 498)
297 isValidTocken?(response.response?.statusCode ?? 498)
480
298
481− if let code = response.response?.statusCode, code == 498 {
482− return
483− }
484−
485 guard let json = response.data else { return }
299 guard let json = response.data else { return }
486
300
487− guard let newPost = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
301+ guard let newPost = try? decoder.decode(QueryPosts.self, from: json) else { return }
488
302
489 completion(newPost.response)
303 completion(newPost.response)
490 }
304 }
@@ -494,7 +308,7 @@ class Model{
494
308
495 static func getUsers(for ids: [Int], completion: @escaping (([Int:Users])->())){
309 static func getUsers(for ids: [Int], completion: @escaping (([Int:Users])->())){
496 let json = "\(Set(ids))"
310 let json = "\(Set(ids))"
497−
311+ print(json)
498 var request = URLRequest(url: usersURL)
312 var request = URLRequest(url: usersURL)
499
313
500 request.httpMethod = "POST"
314 request.httpMethod = "POST"
@@ -508,16 +322,11 @@ class Model{
508
322
509 isValidTocken?(response.response?.statusCode ?? 498)
323 isValidTocken?(response.response?.statusCode ?? 498)
510
324
511− if let code = response.response?.statusCode, code == 498 {
512− return
513− }
514−
515 guard let json = response.data else { return }
325 guard let json = response.data else { return }
516
326
517 guard let users = try? decoder.decode([Users].self, from: json) else { return }
327 guard let users = try? decoder.decode([Users].self, from: json) else { return }
518
328
519 var dict: [Int:Users] = [:]
329 var dict: [Int:Users] = [:]
520−
521 users.forEach({ (user) in
330 users.forEach({ (user) in
522 dict[user.id] = user
331 dict[user.id] = user
523 })
332 })
@@ -529,7 +338,7 @@ class Model{
529 // get channel (with id): in responce -- PostQuery
338 // get channel (with id): in responce -- PostQuery
530 static func getChannel(with channelId: Int, on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
339 static func getChannel(with channelId: Int, on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
531 {
340 {
532− let postRequest = GeneralRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: channelId)
341+ let postRequest = PostsLastRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: channelId)
533 let jsonData = try? JSONEncoder().encode(postRequest)
342 let jsonData = try? JSONEncoder().encode(postRequest)
534
343
535 var request = URLRequest(url: channelsGetURL)
344 var request = URLRequest(url: channelsGetURL)
@@ -544,13 +353,10 @@ class Model{
544
353
545 isValidTocken?(response.response?.statusCode ?? 498)
354 isValidTocken?(response.response?.statusCode ?? 498)
546
355
547− if let code = response.response?.statusCode, code == 498 {
548− return
549− }
550
356
551 guard let json = response.data else { return }
357 guard let json = response.data else { return }
552
358
553− guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
359+ guard let newQueery = try? decoder.decode(QueryPosts.self, from: json) else { return }
554
360
555 idUser = newQueery.users
361 idUser = newQueery.users
556 completion((newQueery.users, newQueery.response))
362 completion((newQueery.users, newQueery.response))
@@ -558,7 +364,7 @@ class Model{
558 }
364 }
559
365
560
366
561− static func createChannel(with channel: Channels, completion: @escaping ((ResultR)->())) {
367+ static func createChannel(with channel: Channels) {
562
368
563 var request = URLRequest(url: channelsCreateURL)
369 var request = URLRequest(url: channelsCreateURL)
564 request.httpMethod = "POST"
370 request.httpMethod = "POST"
@@ -569,13 +375,6 @@ class Model{
569 (response) in
375 (response) in
570
376
571 isValidTocken?(response.response?.statusCode ?? 498)
377 isValidTocken?(response.response?.statusCode ?? 498)
572−
573− if let code = response.response?.statusCode, let result = ResultR(rawValue: code) {
574− completion(result)
575− return
576− }
577−
578− completion(ResultR.internalServerError)
579 }
378 }
580
379
581 }
380 }
@@ -588,9 +387,6 @@ class Model{
588 AF.request(request).responseJSON { (response) in
387 AF.request(request).responseJSON { (response) in
589
388
590 isValidTocken?(response.response?.statusCode ?? 498)
389 isValidTocken?(response.response?.statusCode ?? 498)
591− if let code = response.response?.statusCode, code == 498 {
592− return
593− }
594
390
595 guard let json = response.data else { return }
391 guard let json = response.data else { return }
596
392
@@ -609,9 +405,6 @@ class Model{
609
405
610 AF.request(request).response { (response) in
406 AF.request(request).response { (response) in
611 isValidTocken?(response.response?.statusCode ?? 498)
407 isValidTocken?(response.response?.statusCode ?? 498)
612− if let code = response.response?.statusCode, code == 498 {
613− return
614− }
615 }
408 }
616 completion()
409 completion()
617 }
410 }
@@ -627,9 +420,6 @@ class Model{
627 (response) in
420 (response) in
628
421
629 isValidTocken?(response.response?.statusCode ?? 498)
422 isValidTocken?(response.response?.statusCode ?? 498)
630− if let code = response.response?.statusCode, code == 498 {
631− return
632− }
633 }
423 }
634 }
424 }
635
425
@@ -652,9 +442,6 @@ class Model{
652 }
442 }
653
443
654 isValidTocken?(response.response?.statusCode ?? 498)
444 isValidTocken?(response.response?.statusCode ?? 498)
655− if let code = response.response?.statusCode, code == 498 {
656− return
657− }
658 }
445 }
659 }
446 }
660
447
@@ -717,26 +504,23 @@ class Model{
717 }
504 }
718 }
505 }
719 */
506 */
720− static func getAnonymousChannel(by anonymousChannel: Model.Channels, exclusiveFrom: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->())){
507+ static func getAnonymousChannel(by anonymousChannel: Model.AnonymousChannel, completion: @escaping (((users:[Int: Users], posts:[Posts]))->())){
721
508
722− let req = GeneralRequest<Model.Channels>(limit: 10, exclusiveFrom: exclusiveFrom, request: anonymousChannel)
723−
724 var request = URLRequest(url: channelsGetAnonURL)
509 var request = URLRequest(url: channelsGetAnonURL)
725 request.httpMethod = "POST"
510 request.httpMethod = "POST"
726− request.httpBody = try? JSONEncoder().encode(req)
511+ request.httpBody = try? JSONEncoder().encode(anonymousChannel)
727
512
728 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
513 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
729 AF.request(request).response {
514 AF.request(request).response {
730 (response) in
515 (response) in
731
516
732 isValidTocken?(response.response?.statusCode ?? 498)
517 isValidTocken?(response.response?.statusCode ?? 498)
733− if let code = response.response?.statusCode, code == 498 {
734− return
735− }
736
518
737 guard let json = response.data else { return }
519 guard let json = response.data else { return }
738
520
739− guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
521+ guard let newQueery = try? decoder.decode(QueryPosts.self, from: json) else { return }
522+
523+ // idUser = newQueery.users
740 completion((newQueery.users, newQueery.response))
524 completion((newQueery.users, newQueery.response))
741 }
525 }
742 }
526 }
@@ -745,406 +529,11 @@ class Model{
745
529
746 AF.request(URLRequest(url: hashTagTreeURL)).responseJSON {
530 AF.request(URLRequest(url: hashTagTreeURL)).responseJSON {
747 (response) in
531 (response) in
748− isValidTocken?(response.response?.statusCode ?? 498)
532+
749− if let code = response.response?.statusCode, code == 498 {
750− return
751− }
752 guard let json = response.data else { return }
533 guard let json = response.data else { return }
753 guard let tree = try? decoder.decode(CompletionTree.self, from: json) else { return }
534 guard let tree = try? decoder.decode(CompletionTree.self, from: json) else { return }
754 completion(tree)
535 completion(tree)
755 }
536 }
756 }
537 }
757
538
758− static func getChatAll(limit: Int = 10, exclusiveFrom: Int? = nil, request: [Int] = [], completion: @escaping ((([Dialog],[Int:Model.Users]))->()))
759− {
760− let req = GeneralRequest<[Int]>(limit: limit, exclusiveFrom: exclusiveFrom, request: request)
761− var request = URLRequest(url: chatsGetAllURL)
762− request.httpMethod = "POST"
763− request.httpBody = try? JSONEncoder().encode(req)
764− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
765−
766− AF.request(request).responseJSON { response in
767− isValidTocken?(response.response?.statusCode ?? 498)
768−
769− if let code = response.response?.statusCode, code == 498 {
770− return
771− }
772−
773− guard let json = response.data else { return }
774− let dialogs = try! decoder.decode(QueryPosts<Dialog>.self, from: json)
775−
776− completion((dialogs.response,dialogs.users))
777− }
778− }
779−
780− enum Dialog: Codable
781− {
782− case groupChat(GroupChat)
783− case userChat(UserChat)
784−
785− private enum DialogKeys: CodingKey{
786− case groupChat
787− case userChat
788− }
789−
790− init(from decoder: Decoder) throws {
791− let container = try decoder.container(keyedBy: DialogKeys.self)
792− if container.contains(.groupChat){
793− self = .groupChat(try GroupChat(from: container.superDecoder(forKey: .groupChat)))
794− } else if container.contains(.userChat){
795− self = .userChat(try UserChat(from: container.superDecoder(forKey: .userChat)))
796− } else {
797− throw DecodingError.keyNotFound(DialogKeys.groupChat, DecodingError.Context(codingPath: container.codingPath, debugDescription: "hz"))
798− }
799− }
800−
801− func encode(to encoder: Encoder) throws {
802− var container = encoder.container(keyedBy: DialogKeys.self)
803− switch self{
804− case .groupChat(let chat):
805− try chat.encode(to: container.superEncoder(forKey: .groupChat))
806− case .userChat(let chat):
807− try chat.encode(to: container.superEncoder(forKey: .userChat))
808− }
809− }
810− }
811−
812− struct GroupChat: Codable {
813− var group: Group
814− var lastMessage: LastMessage?
815−
816−
817− init(group: Group, lastMessage: LastMessage? = nil) {
818− self.group = group
819− self.lastMessage = lastMessage
820− }
821− }
822−
823− struct UserChat: Codable {
824− var user: Int
825− var lastMessage: LastMessage?
826−
827− init(user: Int, lastMessage: LastMessage? = nil) {
828− self.user = user
829− self.lastMessage = lastMessage
830− }
831− }
832−
833− struct Group: Codable {
834− var users: [Int: UserPermission]
835− var name: String
836− var id: Int
837−
838− init(users: [Int: UserPermission] = [:], name: String = "", id: Int) {
839− self.id = id
840− self.users = users
841− self.name = name
842− }
843− }
844−
845− struct UserPermission: Codable {
846− var isAdmin: Bool
847− }
848−
849− struct LastMessage: Codable {
850− var body: Attachments
851− var destination: MessageDestination
852− var time: String
853− var author: Int
854− var id: Int
855−
856− enum MessageCodingKeys: CodingKey{
857− case user
858− case group
859− case body
860− case time
861− case author
862− case id
863− }
864−
865− init(from decoder: Decoder) throws
866− {
867− let container = try decoder.container(keyedBy: MessageCodingKeys.self)
868− time = try container.decode(String.self, forKey: .time)
869− body = try container.decode(Attachments.self, forKey: .body)
870− author = try container.decode(Int.self, forKey: .author)
871− id = try container.decode(Int.self, forKey: .id)
872−
873− if container.contains(.user){
874− destination = MessageDestination.userChatDestination(try Int(from: container.superDecoder(forKey: .user)))
875− } else if container.contains(.group){
876− destination = MessageDestination.groupChatDestination(try Int(from: container.superDecoder(forKey: .group)))
877− } else {
878− throw DecodingError.keyNotFound(MessageCodingKeys.group, DecodingError.Context(codingPath: container.codingPath, debugDescription: "hz gr"))
879− }
880− }
881−
882− func encode(to encoder: Encoder) throws {
883− var container = encoder.container(keyedBy: MessageCodingKeys.self)
884−
885− try container.encode(time, forKey: .time)
886− try container.encode(id, forKey: .id)
887− try container.encode(author, forKey: .author)
888− try container.encode(body, forKey: .body)
889−
890− switch destination {
891− case .userChatDestination(let uId):
892− try uId.encode(to: container.superEncoder(forKey: .user))
893− case .groupChatDestination(let gId):
894− try gId.encode(to: container.superEncoder(forKey: .group))
895− }
896− }
897− }
898−
899− enum MessageDestination: Codable
900− {
901− func encode(to encoder: Encoder) throws
902− {
903− var container = encoder.container(keyedBy: MessCodingKeys.self)
904− switch self {
905− case .userChatDestination(let uId):
906− try uId.encode(to: container.superEncoder(forKey: .user))
907− case .groupChatDestination(let gId):
908− try gId.encode(to: container.superEncoder(forKey: .group))
909− }
910− }
911−
912− init(from decoder: Decoder) throws
913− {
914− let container = try decoder.container(keyedBy: MessCodingKeys.self)
915− if container.contains(.user){
916− self = .userChatDestination(try Int(from: container.superDecoder(forKey: .user)))
917− } else if container.contains(.group){
918− self = .groupChatDestination(try Int(from: container.superDecoder(forKey: .group)))
919− } else {
920− throw DecodingError.keyNotFound(MessCodingKeys.group, DecodingError.Context(codingPath: container.codingPath, debugDescription: "hz gr"))
921− }
922− }
923−
924− enum MessCodingKeys: CodingKey{
925− case user
926− case group
927− }
928−
929− case userChatDestination(Int)
930− case groupChatDestination(Int)
931−
932− }
933−
934− static func createGroupChat(from group: Group, completion: @escaping ((Int)->())) {
935− let req = group
936− var request = URLRequest(url: createGroupChatURL)
937− request.httpMethod = "POST"
938− request.httpBody = try? JSONEncoder().encode(req)
939− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
940−
941− AF.request(request).response { (response) in
942−
943− isValidTocken?(response.response?.statusCode ?? 498)
944− if let code = response.response?.statusCode, code == 498 {
945− return
946− }
947−
948− guard let json = response.data else { return }
949− let stringInt = String.init(data: json, encoding: String.Encoding.utf8)
950− let intId = Int.init(stringInt!)
951−
952− completion(intId!)
953− }
954− }
955−
956− static func getMessagesFor(typeOfChat: Model.Dialog, chat id: Int, exclusiveFrom: Int? = nil, limit l: Int = 25, direction: String = "backward", completion: @escaping (([LastMessage])->()))
957− {
958− let req = GeneralRequest<Int>(direction: direction, limit: l, exclusiveFrom: exclusiveFrom, request: id)
959− var request: URLRequest?
960−
961− switch typeOfChat {
962− case .groupChat:
963− request = URLRequest(url: messagesGetGroupChatURL)
964− case .userChat:
965− request = URLRequest(url: messagesGetUserChatURL)
966− }
967−
968− request!.httpMethod = "POST"
969− request!.httpBody = try? JSONEncoder().encode(req)
970− request!.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
971−
972− AF.request(request!).response { (response) in
973−
974− isValidTocken?(response.response?.statusCode ?? 498)
975− if let code = response.response?.statusCode, code == 498 {
976− return
977− }
978−
979− guard let json = response.data else { return }
980− guard let messages = try? decoder.decode([LastMessage].self, from: json) else { return }
981−
982− completion(messages)
983− }
984− }
985−
986− static func leaveGroupChat(id: Int, completion: @escaping (()->()))
987− {
988− var request = URLRequest(url: leaveGroupChatURL)
989− request.httpMethod = "POST"
990− request.httpBody = "\(id)".data(using: .utf8)
991− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
992−
993− AF.request(request).response { (response) in
994− isValidTocken?(response.response?.statusCode ?? 498)
995−
996− if let code = response.response?.statusCode, code == 498 {
997− return
998− }
999− }
1000−
1001− completion()
1002− }
1003−
1004− static func updateGroupChat(with group: Model.Group)
1005− {
1006− var request = URLRequest(url: updateGroupChatURL)
1007− request.httpMethod = "POST"
1008− request.httpBody = try? JSONEncoder().encode(group)
1009− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
1010−
1011− AF.request(request).response { (response) in
1012− isValidTocken?(response.response?.statusCode ?? 498)
1013−
1014− if let code = response.response?.statusCode, code == 498 {
1015− return
1016− }
1017− }
1018−
1019− // completion()
1020− }
1021−
1022− struct SendMessage: Codable {
1023− var body: Attachments
1024− var destination: MessageDestination
1025−
1026− init(from decoder: Decoder) throws
1027− {
1028− let container = try decoder.container(keyedBy: LastMessage.MessageCodingKeys.self)
1029− body = try container.decode(Attachments.self, forKey: .body)
1030−
1031− if container.contains(.user){
1032− destination = MessageDestination.userChatDestination(try Int(from: container.superDecoder(forKey: .user)))
1033− } else if container.contains(.group){
1034− destination = MessageDestination.groupChatDestination(try Int(from: container.superDecoder(forKey: .group)))
1035− } else {
1036− throw DecodingError.keyNotFound(LastMessage.MessageCodingKeys.group, DecodingError.Context(codingPath: container.codingPath, debugDescription: "hz gr1"))
1037− }
1038− }
1039−
1040− func encode(to encoder: Encoder) throws {
1041− var container = encoder.container(keyedBy: LastMessage.MessageCodingKeys.self)
1042− try container.encode(body, forKey: .body)
1043−
1044− switch destination {
1045− case .userChatDestination(let uId):
1046− try uId.encode(to: container.superEncoder(forKey: .user))
1047− case .groupChatDestination(let gId):
1048− try gId.encode(to: container.superEncoder(forKey: .group))
1049− }
1050− }
1051−
1052− init(body: Attachments, destination: MessageDestination)
1053− {
1054− self.body = body
1055− self.destination = destination
1056− }
1057− }
1058−
1059− static func sendMessage(message: SendMessage, completion: @escaping ((ResultR)->())){
1060−
1061− var request = URLRequest(url: messagesSendURL)
1062− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
1063− request.httpMethod = "POST"
1064− request.httpBody = try? JSONEncoder().encode(message)
1065−
1066− AF.request(request).response { (response) in
1067− isValidTocken?(response.response?.statusCode ?? 498)
1068−
1069− if let code = response.response?.statusCode, code == 498 {
1070− return
1071− }
1072−
1073− if let result = ResultR(rawValue: response.response!.statusCode){
1074− completion(result)
1075− } else {
1076− completion(.internalServerError)
1077− }
1078− }
1079− }
1080−
1081− struct Faculty: Codable
1082− {
1083−
1084− var path: String
1085− var url: String
1086− var campusName: String
1087− var campusCode: String
1088− var name: String
1089− var tags: [String]
1090− var address: String
1091−
1092− }
1093−
1094− static func searchFaculty(string: String, completion: @escaping (([Model.Faculty])->()))
1095− {
1096− var request = URLRequest(url: facultySearchURL)
1097− request.httpMethod = "POST"
1098− request.httpBody = string.data(using: .utf8)
1099− request.setValue("text/plain;charset=utf-8", forHTTPHeaderField: "Content-Type")
1100−
1101− AF.request(request).response { (response) in
1102− isValidTocken?(response.response?.statusCode ?? 498)
1103−
1104− if let code = response.response?.statusCode, code == 498 {
1105− return
1106− }
1107−
1108− guard let json = response.data else { return }
1109− guard let faculties = try? decoder.decode([Faculty].self, from: json) else { return }
1110−
1111− completion(faculties)
1112− }
1113− }
1114−
1115− static func userUpdate(with newUser: NewRegistration, completion: @escaping ((Bool)->())) {
1116− var request = URLRequest(url: usersUpdateURL)
1117− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
1118− request.httpMethod = "POST"
1119− request.httpBody = try? JSONEncoder().encode(newUser)
1120−
1121− AF.request(request).response { (response) in
1122− isValidTocken?(response.response?.statusCode ?? 498)
1123−
1124− if let code = response.response?.statusCode, code == 498 {
1125− return
1126− }
1127−
1128− if let code = response.response?.statusCode, code != 204{
1129− completion (false)
1130− } else {
1131− completion(true)
1132− }
1133− }
1134− }
1135−
1136− static func deactivateAll(completion: @escaping (()->())){
1137− var request = URLRequest(url: deactivateURL)
1138− request.httpMethod = "DELETE"
1139−
1140− AF.request(request).response { (responce) in
1141− isValidTocken?(responce.response?.statusCode ?? 498)
1142−
1143− if let code = responce.response?.statusCode, code == 498 {
1144− return
1145− }
1146−
1147− completion()
1148− }
1149− }
1150}
539}
GDproject/Supporting files/Assets.xcassets/chat.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "chat.pdf",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/chat.imageset/chat.pdfdeleted

Binary file not shown.