git.iko.soy/dashared/GDproject
on master help sign in
30 files changed+1555−229
since splitsnapshots
unifiedsplit
GDproject.xcodeproj/project.pbxproj+20−4 GDproject/Base.lproj/Main.storyboard+282−21 GDproject/Controller/ News and channels/ChannelController.swift+1−1 GDproject/Controller/ News and channels/ChannelListController.swift+2−2 GDproject/Controller/ News and channels/ChannelViewController.swift+8−3 GDproject/Controller/ News and channels/FullPostController.swift+2−19 GDproject/Controller/ News and channels/NewPostViewController.swift+26−8 GDproject/Controller/ News and channels/NewsController.swift+3−1 GDproject/Controller/ News and channels/NewsVC.swift+3−1 GDproject/Controller/ News and channels/PostViewCell.swift+2−1 GDproject/Controller/Coordinators/LogInCoordinator.swift+37−8 GDproject/Controller/Coordinators/MessagesCoordinator.swift+7−4 GDproject/Controller/Coordinators/ProfileCoordinator.swift+22−16 GDproject/Controller/Log In/CodeViewController.swift+144 GDproject/Controller/Log In/FacultyTableViewController.swift+88 GDproject/Controller/Log In/InititalsViewCell.swift+23 GDproject/Controller/Log In/LogInCoordinator1.swift−48 GDproject/Controller/Log In/LogInViewController.swift+29−4 GDproject/Controller/Log In/RegisterTableViewController.swift+198 GDproject/Controller/Messages/ChatInfoViewController.swift+25−4 GDproject/Controller/Messages/Dialog/DialogViewController.swift+18−8 GDproject/Controller/Messages/MessageViewCell.swift+38 GDproject/Controller/Messages/MessagesViewController.swift+107−12 GDproject/Controller/Messages/PeopleToWriteViewController.swift−1 GDproject/Controller/Profile/BasicInfoController.swift+16−11 GDproject/Controller/Profile/InfoCell.swift+2−1 GDproject/Controller/Profile/ProfileViewController.swift+99−28 GDproject/DataStorage.swift+8 GDproject/Extentions.swift+30 GDproject/Simple model/Model.swift+315−23
GDproject.xcodeproj/project.pbxproj+20−4
@@ -10,9 +10,14 @@
1010 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */; };
1111 121A8972226B1EAC005EE599 /* TagsSuggestionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */; };
1212 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */; };
13+ 123589FD22899339002F8028 /* MessageViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123589FC22899339002F8028 /* MessageViewCell.swift */; };
1314 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
1415 123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
1516 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 */; };
1621 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57C22171D2A008A3575 /* ProfileViewController.swift */; };
1722 125BD57F22171D73008A3575 /* Extentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57E22171D73008A3575 /* Extentions.swift */; };
1823 125BD5812217314A008A3575 /* NewsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD5802217314A008A3575 /* NewsVC.swift */; };
@@ -23,7 +28,6 @@
2328 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1288B5CD221F1158002BE6B1 /* DataStorage.swift */; };
2429 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */; };
2530 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */; };
26− 1291BE3622218DBF009D3F23 /* LogInCoordinator1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE3522218DBF009D3F23 /* LogInCoordinator1.swift */; };
2731 129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320032279B4270035C7B3 /* MessagesViewController.swift */; };
2832 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320062279B5690035C7B3 /* MessagesCoordinator.swift */; };
2933 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */; };
@@ -105,9 +109,14 @@
105109 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplifiedChannelsList.swift; sourceTree = "<group>"; };
106110 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsSuggestionController.swift; sourceTree = "<group>"; };
107111 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>"; };
108113 123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
109114 123E37A6221F1DD700F6E42A /* MainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
110115 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>"; };
111120 125BD57C22171D2A008A3575 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
112121 125BD57E22171D73008A3575 /* Extentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extentions.swift; sourceTree = "<group>"; };
113122 125BD5802217314A008A3575 /* NewsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsVC.swift; sourceTree = "<group>"; };
@@ -118,7 +127,6 @@
118127 1288B5CD221F1158002BE6B1 /* DataStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStorage.swift; sourceTree = "<group>"; };
119128 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelsCoordinator.swift; sourceTree = "<group>"; };
120129 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbarCoordinator.swift; sourceTree = "<group>"; };
121− 1291BE3522218DBF009D3F23 /* LogInCoordinator1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInCoordinator1.swift; sourceTree = "<group>"; };
122130 129320032279B4270035C7B3 /* MessagesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = "<group>"; };
123131 129320062279B5690035C7B3 /* MessagesCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesCoordinator.swift; sourceTree = "<group>"; };
124132 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PeopleToWriteViewController.swift; path = GDproject/Controller/Messages/PeopleToWriteViewController.swift; sourceTree = SOURCE_ROOT; };
@@ -216,8 +224,11 @@
216224 1291BE3722218DC4009D3F23 /* Log In */ = {
217225 isa = PBXGroup;
218226 children = (
227+ 125A9A912286100800513E2A /* FacultyTableViewController.swift */,
228+ 125A9A8F228609C500513E2A /* InititalsViewCell.swift */,
229+ 125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */,
230+ 125A9A892285C3DA00513E2A /* CodeViewController.swift */,
219231 123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
220− 1291BE3522218DBF009D3F23 /* LogInCoordinator1.swift */,
221232 );
222233 path = "Log In";
223234 sourceTree = "<group>";
@@ -229,6 +240,7 @@
229240 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */,
230241 1298810C227F138C0032ACA3 /* Dialog */,
231242 129320032279B4270035C7B3 /* MessagesViewController.swift */,
243+ 123589FC22899339002F8028 /* MessageViewCell.swift */,
232244 );
233245 path = Messages;
234246 sourceTree = "<group>";
@@ -425,11 +437,11 @@
425437 files = (
426438 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */,
427439 124CC7032221C00C009DF531 /* Model.swift in Sources */,
440+ 125A9A90228609C500513E2A /* InititalsViewCell.swift in Sources */,
428441 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */,
429442 12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */,
430443 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
431444 12D7D137221D78E800B35452 /* Channel.swift in Sources */,
432− 1291BE3622218DBF009D3F23 /* LogInCoordinator1.swift in Sources */,
433445 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */,
434446 125BD5812217314A008A3575 /* NewsVC.swift in Sources */,
435447 12E36DB72214400A006FCDD7 /* Post.swift in Sources */,
@@ -440,10 +452,14 @@
440452 1261BB9E227B793D003898CF /* ChatInfoViewController.swift in Sources */,
441453 12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */,
442454 1298810B227F13840032ACA3 /* DialogCell.swift in Sources */,
455+ 125A9A922286100800513E2A /* FacultyTableViewController.swift in Sources */,
456+ 125A9A8E2286068A00513E2A /* RegisterTableViewController.swift in Sources */,
457+ 123589FD22899339002F8028 /* MessageViewCell.swift in Sources */,
443458 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */,
444459 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */,
445460 125BD57F22171D73008A3575 /* Extentions.swift in Sources */,
446461 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */,
462+ 125A9A8A2285C3DA00513E2A /* CodeViewController.swift in Sources */,
447463 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */,
448464 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */,
449465 12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */,
GDproject/Base.lproj/Main.storyboard+282−21
@@ -231,6 +231,250 @@
231231 </objects>
232232 <point key="canvasLocation" x="2799" y="1979"/>
233233 </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>
234478 <!--Simplified Channels List-->
235479 <scene sceneID="gAa-jy-vpG">
236480 <objects>
@@ -534,29 +778,53 @@
534778 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
535779 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
536780 <prototypes>
537− <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">
538− <rect key="frame" x="0.0" y="28" width="375" height="44"/>
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">
782+ <rect key="frame" x="0.0" y="28" width="375" height="78"/>
539783 <autoresizingMask key="autoresizingMask"/>
540784 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="67C-fT-WEV" id="O3b-Xv-UNk">
541− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
785+ <rect key="frame" x="0.0" y="0.0" width="375" height="77.5"/>
542786 <autoresizingMask key="autoresizingMask"/>
543787 <subviews>
544− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9br-gb-mg8">
545− <rect key="frame" x="16" y="5" width="33.5" height="20.5"/>
546− <autoresizingMask key="autoresizingMask"/>
547− <fontDescription key="fontDescription" type="system" pointSize="17"/>
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">
798+ <rect key="frame" x="16" y="11" width="46" height="22"/>
799+ <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
548800 <nil key="textColor"/>
549801 <nil key="highlightedColor"/>
550802 </label>
551− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Jxd-We-VyC">
552− <rect key="frame" x="16" y="25.5" width="33" height="14.5"/>
553− <autoresizingMask key="autoresizingMask"/>
554− <fontDescription key="fontDescription" type="system" pointSize="12"/>
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">
804+ <rect key="frame" x="16" y="49" width="343" height="18"/>
805+ <fontDescription key="fontDescription" type="system" pointSize="15"/>
555806 <nil key="textColor"/>
556807 <nil key="highlightedColor"/>
557808 </label>
558809 </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>
559822 </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>
560828 </tableViewCell>
561829 </prototypes>
562830 <connections>
@@ -567,7 +835,7 @@
567835 </tableViewController>
568836 <placeholder placeholderIdentifier="IBFirstResponder" id="fu3-z4-EY7" userLabel="First Responder" sceneMemberID="firstResponder"/>
569837 </objects>
570− <point key="canvasLocation" x="2798" y="932"/>
838+ <point key="canvasLocation" x="2681" y="918"/>
571839 </scene>
572840 <!--People To Write View Controller-->
573841 <scene sceneID="6Td-bq-Ebf">
@@ -578,7 +846,7 @@
578846 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
579847 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
580848 <prototypes>
581− <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">
849+ <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="peopleToWriteCell" textLabel="e4H-yo-W57" style="IBUITableViewCellStyleDefault" id="5ue-Sf-Blf">
582850 <rect key="frame" x="0.0" y="28" width="375" height="44"/>
583851 <autoresizingMask key="autoresizingMask"/>
584852 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5ue-Sf-Blf" id="8Dr-YE-x7M">
@@ -586,14 +854,7 @@
586854 <autoresizingMask key="autoresizingMask"/>
587855 <subviews>
588856 <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="e4H-yo-W57">
589− <rect key="frame" x="16" y="12" width="33.5" height="20.5"/>
590− <autoresizingMask key="autoresizingMask"/>
591− <fontDescription key="fontDescription" type="system" pointSize="17"/>
592− <nil key="textColor"/>
593− <nil key="highlightedColor"/>
594− </label>
595− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QSb-Bd-4gu">
596− <rect key="frame" x="315" y="12" width="44" height="20.5"/>
857+ <rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
597858 <autoresizingMask key="autoresizingMask"/>
598859 <fontDescription key="fontDescription" type="system" pointSize="17"/>
599860 <nil key="textColor"/>
GDproject/Controller/ News and channels/ChannelController.swift+1−1
@@ -73,7 +73,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
7373 if let _ = channel?.id { print("update")
7474 Model.updateChannel(with: channel!)
7575 } else { print("create")
76− Model.createChannel(with: channel!)
76+ //Model.createChannel(with: channel!)
7777 }
7878 return
7979 }
GDproject/Controller/ News and channels/ChannelListController.swift+2−2
@@ -30,7 +30,7 @@ class ChannelListController: UITableViewController {
3030 var displayingChannel: Model.Channels?
3131
3232 var toReload: Bool = false {
33− didSet{
33+ didSet {
3434 tableView.reloadData()
3535 }
3636 }
@@ -100,7 +100,7 @@ class ChannelListController: UITableViewController {
100100 @objc func addChannel()
101101 {
102102 // editing mode is on automatically
103− onEditingModeBegins?(Model.Channels(people: [], name: "Untitled", tags: []),IndexPath(row: 1, section: 0))
103+ onEditingModeBegins?(Model.Channels(people: [], name: "Untitled", id: 0, tags: []),IndexPath(row: 1, section: 0))
104104 }
105105
106106 static let generalChannel = Model.Channels(people: [], name: "General", id: -1, tags: [])
GDproject/Controller/ News and channels/ChannelViewController.swift+8−3
@@ -60,12 +60,17 @@ class ChannelViewController: UITableViewController, UpdatableName, UpdatableChan
6060 super.viewWillDisappear(animated)
6161 }
6262
63− guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else {
64− if let _ = channel?.id
63+ guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else
64+ {
65+ if let id = channel?.id, id != 0
6566 {
6667 Model.updateChannel(with: channel!)
6768 } else {
68− Model.createChannel(with: channel!)
69+ Model.createChannel(with: channel!) {
70+ [weak self] in
71+ self?.showAlertOn(result: $0)
72+ return
73+ }
6974 }
7075 return
7176 }
GDproject/Controller/ News and channels/FullPostController.swift+2−19
@@ -25,27 +25,10 @@ class FullPostController: UITableViewController {
2525
2626 func setUpNavigationBar(){
2727 navigationItem.largeTitleDisplayMode = .never
28− navigationItem.title = "\(post?.authorId ?? 0)"
29− navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(self.options))]
28+ navigationItem.title = "Post"
3029 }
3130
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− }
31+
4932 // MARK: - Table view data source
5033
5134 override func numberOfSections(in tableView: UITableView) -> Int {
GDproject/Controller/ News and channels/NewPostViewController.swift+26−8
@@ -41,7 +41,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
4141 let textStorage = MarklightTextStorage()
4242
4343 static var draft: String = ""
44− static var hashTagsDraft: [String] = ["tt"]
44+ static var hashTagsDraft: [String] = [ ]
4545
4646 var textView: UITextView!
4747
@@ -72,7 +72,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
7272
7373 setUpMD()
7474 setUpTextView()
75− setUpAccessoryView()
75+ // setUpAccessoryView()
7676 //setUpTagsView()
7777 }
7878
@@ -109,7 +109,8 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
109109 override func viewWillAppear(_ animated: Bool) {
110110 super.viewWillAppear(animated)
111111
112− navigationController?.navigationBar.prefersLargeTitles = false
112+ //navigationController?.navigationBar.prefersLargeTitles = false
113+ navigationItem.largeTitleDisplayMode = .never
113114 navigationItem.title = "New post"
114115 textView.text = NewPostViewController.draft
115116 // tagsField.addTags(NewPostViewController.hashTagsDraft)
@@ -140,7 +141,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
140141 func setUpTextView(){
141142 view.addConstraint(bottomTextViewConstraint)
142143 view1.addSubview(textView)
143− textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(40+8) + .right(8))
144+ textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(8) + .right(8))
144145
145146 if #available(iOS 11.0, *) {
146147 textView.smartDashesType = .no
@@ -209,7 +210,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
209210 }
210211
211212 func setUpMD(){
212− textStorage.marklightTextProcessor.codeColor = UIColor.orange
213+ textStorage.marklightTextProcessor.codeColor = UIColor.gray
213214 textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
214215 textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
215216 textStorage.marklightTextProcessor.codeFontName = "Courier"
@@ -231,10 +232,27 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
231232 var indexOfPost = 0
232233 // MARK:- new post
233234 @objc func newPost(){
234− Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: currentTags)
235+ self.navigationItem.title = "Sending..."
236+ Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: currentTags) {
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 = []
235253 // adding row to uiTableView after adding new post
236254 // myProtocol?.addPost(post: p)
237− moveBackToParentVC?()
255+ // moveBackToParentVC?()
238256 // somewhere here i will be sending server notifications about new post arrival
239257 }
240258
@@ -246,7 +264,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
246264 [weak self]
247265 _ in
248266 NewPostViewController.draft = self?.textView.text ?? ""
249− NewPostViewController.hashTagsDraft = /*self?.tagsField.tags.map { $0.text } ??*/ []
267+ NewPostViewController.hashTagsDraft = self?.currentTags ?? []
250268 self?.moveBackToParentVC?()
251269 }
252270
GDproject/Controller/ News and channels/NewsController.swift+3−1
@@ -52,6 +52,7 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
5252 let updater = TagsSuggestionController()
5353 updater.delegate = self
5454 searchController = UISearchController(searchResultsController: updater)
55+ navigationItem.largeTitleDisplayMode = .always
5556
5657 navigationController?.navigationBar.prefersLargeTitles = true
5758 navigationItem.title = "Loading ..."
@@ -81,7 +82,7 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
8182 searchController?.searchBar.placeholder = "Search tags"
8283 }
8384
84− @objc func refreshPostsData( _ ff: UIRefreshControl){
85+ @objc func refreshPostsData( _ ff: UIRefreshControl) {
8586 decideWhatChannelDisplay()
8687 }
8788
@@ -121,6 +122,7 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
121122 }
122123 }
123124 default:
125+ refreshContr.endRefreshing()
124126 break
125127 }
126128
GDproject/Controller/ News and channels/NewsVC.swift+3−1
@@ -19,7 +19,9 @@ struct PostCellData{
1919
2020 let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
2121 markdownParser.enabledElements = .disabledAutomaticLink
22− markdownParser.code.textBackgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
22+ markdownParser.code.font = UIFont(name: "Menlo", size: 16)
23+ markdownParser.code.textBackgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
24+ markdownParser.code.color = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
2325
2426 return markdownParser.parse(markdown)
2527 }
GDproject/Controller/ News and channels/PostViewCell.swift+2−1
@@ -42,6 +42,7 @@ class PostViewCell: UITableViewCell
4242
4343 let shareButton: UIButton = {
4444 let button = UIButton(type: UIButton.ButtonType.detailDisclosure)
45+ button.isHidden = true
4546 return button
4647 }()
4748
@@ -86,7 +87,7 @@ class PostViewCell: UITableViewCell
8687 nameLabel.setTitle("\(post.user?.firstName ?? "") \(post.user?.lastName ?? "")", for: .normal)
8788 nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
8889 if let user = post.user{
89− fullNameLabel.text = "\(user.firstName) \(user.middleName) \(user.lastName)"
90+ fullNameLabel.text = "\(user.faculty.name)"
9091 }
9192 else {
9293 fullNameLabel.text = "\(post.authorId)"
GDproject/Controller/Coordinators/LogInCoordinator.swift+37−8
@@ -10,6 +10,8 @@ import UIKit
1010
1111class LogInCoordinator: BaseCoordinator {
1212
13+ let storyboard = UIStoryboard(name: "Main", bundle: nil)
14+
1315 var didEndFlow: (()->())?
1416 var window: UIWindow!
1517 var navigationController: UINavigationController?
@@ -22,20 +24,47 @@ class LogInCoordinator: BaseCoordinator {
2224
2325 override func start(){
2426 let logInVC = LogInViewController()
25− logInVC.authenticate = { [weak self] (id) in
27+ logInVC.authenticate = { [weak self, weak logInVC] (email) in
2628
27− Model.authenticate(with: id) {
28− (res) in
29+ DataStorage.standard.setEmail(email: email)
30+ Model.authenticate(with: email) { [weak self]
31+ (authStatus) in
32+
33+ print(authStatus.userStatus)
2934
30− if (res) {
31− DataStorage.standard.setUserKey(with: id)
32− self?.didEndFlow?()
35+ if (authStatus.userStatus == "invalid") {
36+ logInVC?.presentAlertInvalidCode()
3337 }
34− else {
35− DataStorage.standard.setUserKey(with: 0)
38+ else if (authStatus.userStatus == "canRegister") { // register form
39+ self?.presentRegisterVC()
40+ } else { // validation code
41+ self?.presentViewControllerForCodeInput()
3642 }
3743 }
3844 }
45+
3946 navigationController?.pushViewController(logInVC, animated: false)
4047 }
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+
4170}
GDproject/Controller/Coordinators/MessagesCoordinator.swift+7−4
@@ -33,14 +33,14 @@ class MessagesCoordinator: BaseCoordinator {
3333
3434 let newVC = self.storyboard.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
3535
36− newVC.whatToDoWithSelection = { [weak newVC, weak self] in
36+ newVC.whatToDoWithSelection = { [weak newVC, weak self] people in
3737 newVC?.navigationController?.popViewController(animated: true)
3838
3939 // detect is it a user or group dialog
40− let count = $0.count
40+ let count = people.count
4141 if count == 1 {
4242
43− let user = $0.first!.key
43+ let user = people.first!.key
4444 let createdDialog = Model.Dialog.userChat(Model.UserChat(user: user))
4545
4646 let vc = DialogViewController()
@@ -49,11 +49,14 @@ class MessagesCoordinator: BaseCoordinator {
4949 self?.navigationController?.pushViewController(vc, animated: true)
5050
5151 } else {
52− var group = Model.Group(users: $0, name: "Untitled", id: 0)
52+ var group = Model.Group(users: people, name: "Untitled", id: 0)
53+ group.users[DataStorage.standard.getUserId()] = Model.UserPermission(isAdmin: true)
54+
5355 Model.createGroupChat(from: group, completion: { [weak self] id in
5456
5557 let newVC1 = DialogViewController()
5658 group.id = id
59+ newVC1.users = Model.Channels.fullPeopleDict
5760 newVC1.dialog = Model.Dialog.groupChat(Model.GroupChat(group: group))
5861 self?.navigationController?.pushViewController(newVC1, animated: true)
5962 })
GDproject/Controller/Coordinators/ProfileCoordinator.swift+22−16
@@ -27,28 +27,34 @@ class ProfileCoordinator: BaseCoordinator {
2727 let storyboard = UIStoryboard(name: "Main", bundle: nil)
2828 let profile = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
2929
30− profile.logOut = { [weak self] in
31− DataStorage.standard.setIsLoggedIn(value: false, with: 0)
32− self?.didEndSession?()
30+ profile.logOut = {
31+ Model.logout() {
32+ [weak self] in
33+
34+ DataStorage.standard.setIsLoggedIn(value: false, with: 0)
35+ self?.didEndSession?()
36+ }
3337 }
3438
35− profile.onSettings = { [weak self, weak storyboard] in
36− let vc = storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
37− self?.navigationController?.pushViewController(vc, animated: true)
39+ profile.deleteAllSessions = {
40+ Model.deactivateAll() {
41+ [weak self] in
42+
43+ DataStorage.standard.setIsLoggedIn(value: false, with: 0)
44+ self?.didEndSession?()
45+ }
3846 }
3947
40− profile.onChannelsListToAddAPerson = { [weak self, weak storyboard] (user) in
41− let vc = storyboard?.instantiateViewController(withIdentifier: simplifiedChannelsList) as! SimplifiedChannelsList
42− vc.user = user
48+ profile.onSettings = { [weak self, weak storyboard, weak profile] in
49+
50+ let vc = storyboard?.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
51+ vc.delegate = profile
52+ vc.userActive = profile?.user
4353
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)
50− self?.navigationController?.pushViewController(vc, animated: false)
54+ self?.navigationController?.pushViewController(vc, animated: true)
5155 }
56+
57+
5258 navigationController?.setViewControllers([profile], animated: false)
5359 }
5460}
GDproject/Controller/Log In/CodeViewController.swiftnew file+144
@@ -0,0 +1,144 @@
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.swiftnew file+88
@@ -0,0 +1,88 @@
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.swiftnew file+23
@@ -0,0 +1,23 @@
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.swiftdeleted−48
@@ -1,48 +0,0 @@
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+29−4
@@ -14,7 +14,24 @@ import Result
1414
1515class LogInViewController: UIViewController {
1616
17− var authenticate: ((Int)->())?
17+ var loading = UIActivityIndicatorView(style: .gray)
18+
19+ var authenticate: ((String)->())?
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+ }
1835
1936 let logInLabel: UILabel = {
2037 let label = UILabel()
@@ -30,6 +47,8 @@ class LogInViewController: UIViewController {
3047 textField.placeholder = "Mail"
3148 textField.borderStyle = .roundedRect
3249 textField.textColor = .black
50+ textField.autocorrectionType = UITextAutocorrectionType.no
51+ textField.autocapitalizationType = UITextAutocapitalizationType.none
3352 textField.clearButtonMode = .always
3453 return textField
3554 }()
@@ -45,7 +64,8 @@ class LogInViewController: UIViewController {
4564 }()
4665
4766 @objc func handleTap(){
48− authenticate?(Int(mailTextField.text!)!)
67+ loading.startAnimating()
68+ authenticate?(mailTextField.text!)
4969 }
5070
5171 private lazy var keyboardBar = UIView()
@@ -55,6 +75,10 @@ class LogInViewController: UIViewController {
5575 func setUpView(){
5676 // logIn stack with textField and label
5777 view.addSubview(contentView)
78+ view.addSubview(loading)
79+
80+ loading.centerInSuperview()
81+
5882 contentView.edgesToSuperview(excluding: .bottom, insets: .left(16) + .right(16) + .top(80), usingSafeArea: true)
5983 let views = [logInLabel, mailTextField]
6084 contentView.stack(views, axis: .vertical, spacing: 10)
@@ -62,6 +86,7 @@ class LogInViewController: UIViewController {
6286
6387 func configureKeyboard(){
6488
89+ mailTextField.keyboardType = .emailAddress
6590 // configure keyboardBar setUp
6691 view.addSubview(keyboardBar)
6792 keyboardBar.height(50)
@@ -72,14 +97,14 @@ class LogInViewController: UIViewController {
7297 // configure keyboardBar components
7398 keyboardBar.addSubview(logInButton)
7499 logInButton.height(50)
75− logInButton.leftToSuperview(view.leftAnchor, offset: 16, relation: .equal, isActive: true)
100+ logInButton.rightToSuperview(view.rightAnchor, offset: -16, relation: .equal, isActive: true)
76101
77102 }
78103
79104 func logicOfLogInInputValidation() -> ((String?)->()) {
80105
81106 let logic: ((String?)->()) = { [weak self] (someText) in
82− if let text = someText, !text.isEmpty, let _ = Int(text) {
107+ if let text = someText, !text.isEmpty, text.contains("@") {
83108 self?.logInButton.isEnabled = true
84109 } else {
85110 self?.logInButton.isEnabled = false
GDproject/Controller/Log In/RegisterTableViewController.swiftnew file+198
@@ -0,0 +1,198 @@
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.swift+25−4
@@ -91,10 +91,12 @@ class ChatInfoViewController: UITableViewController {
9191 switch indexPath.section {
9292 case 0:
9393 cell.textLabel?.text = groupChat!.name
94+ cell.selectionStyle = .none
9495 return cell
9596 case 1:
9697 cell.textLabel?.text = "Leave chat"
9798 cell.textLabel?.textColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
99+ cell.selectionStyle = .none
98100 return cell
99101 default:
100102 switch myPermissions{
@@ -104,6 +106,7 @@ class ChatInfoViewController: UITableViewController {
104106 case .ordinary:
105107 cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
106108 }
109+ cell.selectionStyle = .none
107110 return cell
108111 }
109112 }
@@ -114,7 +117,7 @@ class ChatInfoViewController: UITableViewController {
114117 case .ordinary:
115118 cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
116119 }
117−
120+ cell.selectionStyle = .none
118121 return cell
119122 }
120123
@@ -143,9 +146,9 @@ class ChatInfoViewController: UITableViewController {
143146
144147
145148 func editName(for cell: UITableViewCell){
146− let alert = UIAlertController(title: "Вы уверены?", message: "Название:", preferredStyle: .alert)
149+ let alert = UIAlertController(title: "Are you sure?", message: "Title:", preferredStyle: .alert)
147150
148− let action1 = UIAlertAction(title: "Oтмена", style: .cancel, handler: nil)
151+ let action1 = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
149152
150153 alert.addTextField { [weak self] (tf) in
151154 tf.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
@@ -194,10 +197,28 @@ class ChatInfoViewController: UITableViewController {
194197 case .admin:
195198 showUserChoiceVC()
196199 default:
197− break
200+ showParticipantPage(with: usersArray[indexPath.row])
198201 }
199202 }
200203 }
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+ }
201222 }
202223
203224 func showUserChoiceVC()
GDproject/Controller/Messages/Dialog/DialogViewController.swift+18−8
@@ -61,7 +61,9 @@ class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegat
6161
6262 self.tableView.delegate = self
6363 self.tableView.dataSource = self
64−
64+
65+ tableView.setContentOffset(CGPoint(x: 0, y: 50), animated: false)
66+
6567 navigationItem.largeTitleDisplayMode = .never
6668
6769 tableView.keyboardDismissMode = .onDrag
@@ -114,6 +116,7 @@ class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegat
114116 let button = UIButton()
115117 button.setTitle("Send", for: .normal)
116118 button.setTitleColor(.blue, for: .normal)
119+ button.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
117120 button.addTarget(self, action: #selector(sendMessage), for: .touchUpInside)
118121 return button
119122 }()
@@ -132,8 +135,13 @@ class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegat
132135 {
133136 Model.sendMessage(message: Model.SendMessage(body: Model.Attachments(markdown: messageTextView.text), destination: destination)) { [unowned self] in
134137
135− self.getMessagesNew(for: self.dialog!)
136− self.messageTextView.text = ""
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+ }
137145 }
138146
139147 prevLast = -1
@@ -158,7 +166,7 @@ class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegat
158166
159167 messageSendView.edgesToSuperview(excluding: [.top,.bottom])
160168
161− bottomConstraint = NSLayoutConstraint(item: messageSendView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
169+ bottomConstraint = NSLayoutConstraint(item: messageSendView, attribute: .bottom, relatedBy: .equal, toItem: self.view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
162170 view.addConstraint(bottomConstraint)
163171
164172 messageSendView.height(60)
@@ -191,7 +199,7 @@ class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegat
191199
192200 let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
193201
194− bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? -(keyBoardFrame.height) : 0
202+ bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? -(keyBoardFrame.height) + self.view.safeAreaInsets.bottom : 0
195203
196204 UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
197205 self.view.layoutIfNeeded()
@@ -223,6 +231,7 @@ class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegat
223231
224232 vc.delegate = self
225233 vc.users = users!
234+ vc.onUserDiplay = onUserDisplay
226235
227236 if let groupChat = groupChat {
228237 vc.groupChat = groupChat.group
@@ -248,12 +257,13 @@ class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegat
248257 return cellData.count
249258 }
250259
251− override func viewWillAppear(_ animated: Bool) {
260+ override func viewWillAppear(_ animated: Bool)
261+ {
252262 super.viewWillAppear(animated)
253263 tabBarController?.tabBar.isHidden = true
254264
255265 if let dialog = dialog {
256− getMessages(for: dialog)
266+ getMessagesNew(for: dialog)
257267 }
258268 }
259269
@@ -313,7 +323,7 @@ class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegat
313323 var canBePaginated = false
314324 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
315325 {
316− if indexPath.row == cellData.count - 1 && prevLast != indexPath.row && canBePaginated
326+ if indexPath.row == cellData.count - 1 && prevLast != indexPath.row && canBePaginated && cellData.count >= 24
317327 {
318328 print("exclusiveFrom \(currentMessagesInChat.last?.id ?? 0)")
319329 if let dialog = dialog
GDproject/Controller/Messages/MessageViewCell.swiftnew file+38
@@ -0,0 +1,38 @@
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+107−12
@@ -8,8 +8,44 @@
88
99import UIKit
1010
11−class MessagesViewController: UITableViewController {
11+protocol SelectableDialog: class {
12+ func openDialog(with dialog: Model.Dialog)
13+}
1214
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+
1349 // curreent Active which can be displayed
1450 var currentActiveDialogs: [Model.Dialog] = [] {
1551 didSet {
@@ -17,6 +53,17 @@ class MessagesViewController: UITableViewController {
1753 }
1854 }
1955
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+
2067 // curreent users
2168 var users: [Int: Model.Users] = [:]
2269
@@ -24,17 +71,22 @@ class MessagesViewController: UITableViewController {
2471
2572 var onDialogDisplay: (((dialog: Model.Dialog, users: [Int:Model.Users]))->())?
2673
27− let searchC = UISearchController(searchResultsController: nil)
74+ var searchController: UISearchController?
2875
2976 override func viewDidLoad() {
3077 super.viewDidLoad()
31−
78+
79+ let updater = SuggestedDialogsTableViewController()
80+
81+ updater.delegate = self
82+ searchController = UISearchController(searchResultsController: updater)
83+
3284 // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
3385 self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Write", style: .plain, target: self, action: #selector(choosePerson))
3486
3587 self.navigationItem.title = "Messages"
3688 // self.navigationItem.largeTitleDisplayMode = .always
37− self.navigationItem.searchController = searchC
89+ setUpSearchContr()
3890 navigationController?.navigationBar.prefersLargeTitles = true
3991 self.navigationItem.hidesSearchBarWhenScrolling = false
4092 }
@@ -64,18 +116,15 @@ class MessagesViewController: UITableViewController {
64116
65117 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
66118 {
67− let cell = tableView.dequeueReusableCell(withIdentifier: "MessagesCell", for: indexPath)
119+ let cell = tableView.dequeueReusableCell(withIdentifier: "MessageViewCell", for: indexPath) as! MessageViewCell
68120
69121 switch currentActiveDialogs[indexPath.row].self {
70−
71− case .groupChat(let group):
72− cell.textLabel?.text = group.group.name
73− cell.detailTextLabel?.text = group.lastMessage!.body.markdown
122+ case .groupChat:
123+ cell.fill(with: currentActiveDialogs[indexPath.row])
74124 case .userChat(let userChat):
75− cell.textLabel?.text = "👤 \(users[userChat.user]!.fullName())"
76− cell.detailTextLabel?.text = userChat.lastMessage!.body.markdown
125+ cell.fill(with: currentActiveDialogs[indexPath.row], user: users[userChat.user])
77126 }
78−
127+
79128 return cell
80129 }
81130
@@ -84,3 +133,49 @@ class MessagesViewController: UITableViewController {
84133 onDialogDisplay?(tuple)
85134 }
86135}
136+
137+
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+ }
161+
162+ override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
163+ {
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
175+ }
176+
177+ override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
178+ delegate?.openDialog(with: currentDialogs[indexPath.row])
179+ // self.dismiss(animated: true)
180+ }
181+}
GDproject/Controller/Messages/PeopleToWriteViewController.swift−1
@@ -53,7 +53,6 @@ class PeopleToWriteViewController: UITableViewController {
5353 let cell = tableView.dequeueReusableCell(withIdentifier: "peopleToWriteCell", for: indexPath)
5454
5555 cell.textLabel?.text = users[indexPath.row].fullName()
56− cell.detailTextLabel?.text = "\(users[indexPath.row].id)"
5756
5857 return cell
5958 }
GDproject/Controller/Profile/BasicInfoController.swift+16−11
@@ -16,17 +16,20 @@ struct CellData{
1616
1717class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
1818
19− var dataSourse: [CellData] = [
20− CellData(opened: false, title: "Phone", sectionData: ["+7 901 733 01 79"]),
21− CellData(opened: false, title: "Mail", sectionData: ["vbogomazova@edu.hse.ru"]),
22− CellData(opened: false, title: "Research ID", sectionData: ["4567834336789456737"]),
23− CellData(opened: false, title: "Published", sectionData: ["Это будет очень длинное название книги 1, чтобы сделать проверку", "Книга 2", "Книга 3"]),
24− CellData(opened: false, title: "Courses", sectionData: ["Курс 1", "Курс 2"]),
25− CellData(opened: false, title: "Link", sectionData: ["https://wwww.hse.ru"])
26− ]
19+ var userInfo: Model.Users? {
20+ didSet {
21+ if let userInfo = userInfo {
22+ dataSourse = [CellData(opened: false, title: "Contacts", sectionData: [userInfo.email, userInfo.faculty.address]),
23+ CellData(opened: false, title: "Faculty", sectionData: [userInfo.faculty.campusName, userInfo.faculty.name, userInfo.faculty.address, userInfo.faculty.path]),
24+ CellData(opened: false, title: "Interests", sectionData: userInfo.faculty.tags)]
25+ }
26+ }
27+ }
28+
29+ var dataSourse: [CellData] = [ ]
2730
2831 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
29− if (dataSourse[section].opened){
32+ if (dataSourse[section].opened) {
3033 return dataSourse[section].sectionData.count + 1
3134 } else {
3235 return 1
@@ -45,8 +48,10 @@ class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDat
4548 cell.selectionStyle = .none
4649 return cell
4750 } else {
48− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
49− cell.textLabel?.text = dataSourse[indexPath.section].sectionData[indexPath.row - 1]
51+ let cell = tableView.dequeueReusableCell(withIdentifier: infoCellId, for: indexPath) as! InfoCell
52+ cell.fill(title: dataSourse[indexPath.section].sectionData[indexPath.row - 1])
53+ cell.accessoryType = .none
54+ cell.selectionStyle = .none
5055 return cell
5156 }
5257 }
GDproject/Controller/Profile/InfoCell.swift+2−1
@@ -16,8 +16,9 @@ class InfoCell: UITableViewCell{
1616 label.font = UIFont.systemFont(ofSize: 16)
1717 label.sizeToFit()
1818 label.isScrollEnabled = false
19− label.isUserInteractionEnabled = false
19+ // label.isUserInteractionEnabled = false
2020 label.isEditable = false
21+ label.dataDetectorTypes = .all
2122 label.textColor = .black
2223 return label
2324 }()
GDproject/Controller/Profile/ProfileViewController.swift+99−28
@@ -9,8 +9,17 @@
99import UIKit
1010import TinyConstraints
1111
12−class ProfileViewController: UIViewController
12+protocol UpdateUser: class {
13+ func updateUserObj(with user: Model.Users)
14+}
15+
16+class ProfileViewController: UIViewController, UpdateUser
1317{
18+ func updateUserObj(with user: Model.Users)
19+ {
20+ self.user = user
21+ Model.Channels.fullPeopleDict[user.id] = user
22+ }
1423
1524 @IBOutlet weak var segmentedControl: UISegmentedControl!
1625
@@ -32,6 +41,8 @@ class ProfileViewController: UIViewController
3241
3342 var logOut: (()->())?
3443
44+ var deleteAllSessions: (()->())?
45+
3546 var onSettings: (()->())?
3647
3748 @IBAction func sendMessage(_ sender: UIButton)
@@ -46,17 +57,15 @@ class ProfileViewController: UIViewController
4657 }
4758 }
4859
49− var onChannelsListToAddAPerson: ((Model.Users)->())?
50−
51− var protoDictionary: [Int: UIImage] = [9: #imageLiteral(resourceName: "9"), 5051: #imageLiteral(resourceName: "5051"), 69: #imageLiteral(resourceName: "69"), 42: #imageLiteral(resourceName: "42")]
60+ var protoDictionary: [String: UIImage] = ["135213": #imageLiteral(resourceName: "9"), "135288": #imageLiteral(resourceName: "5051"), "22723" : #imageLiteral(resourceName: "69"), "135083": #imageLiteral(resourceName: "42")]
5261
5362 func fill(with user: Model.Users)
5463 {
55− self.facultyLabel.text = "Студент: Факультет Компьютерных Наук"
64+ self.facultyLabel.text = user.faculty.name
5665 self.nameLabel.text = "\(user.firstName) \(user.middleName)"
5766 self.surnameLabel.text = "\(user.lastName)"
58− self.profileImageView.image = protoDictionary[user.id]?.roundedImage
59− self.placeLabel.text = "📍Москва, Кочновский пр.3"
67+ self.profileImageView.image = protoDictionary[user.faculty.campusCode]?.roundedImage
68+ self.placeLabel.text = "📍\(user.faculty.address)"
6069 if user.id == DataStorage.standard.getUserId() {
6170 newMessageButton.isHidden = true
6271 } else {
@@ -66,8 +75,14 @@ class ProfileViewController: UIViewController
6675
6776 var user: Model.Users? {
6877 didSet {
69− self.fill(with: user!)
70− navigationItem.title = "\(user!.firstName) \(user!.lastName)"
78+ if let user = user {
79+ self.fill(with: user)
80+ navigationItem.title = "\(user.firstName) \(user.lastName)"
81+ } else if let id = idProfile {
82+ Model.getUsers(for: [id]) { [unowned self ] in
83+ self.user = $0[id]
84+ }
85+ }
7186 }
7287 }
7388
@@ -100,6 +115,15 @@ class ProfileViewController: UIViewController
100115 posts.type = .NONE
101116 posts.currChannel = channel
102117
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+
103127 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
104128
105129 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
@@ -135,7 +159,7 @@ class ProfileViewController: UIViewController
135159 }
136160
137161 func setUpNavigarionBar(){
138− navigationController?.navigationBar.prefersLargeTitles = true
162+ // navigationController?.navigationBar.prefersLargeTitles = true
139163 let uibarbutton = UIBarButtonItem(title: "More", style: .plain, target: self, action: #selector(showInformation))
140164 navigationItem.rightBarButtonItems = [uibarbutton]
141165 navigationItem.largeTitleDisplayMode = .always
@@ -145,29 +169,75 @@ class ProfileViewController: UIViewController
145169
146170 let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
147171
148− let channelAction = UIAlertAction(title: "Add to a channel", style: .default){
149− [weak self] (_) in
150− self?.onChannelsListToAddAPerson?(self!.user!)
151− }
152−
153− let settingsAction = UIAlertAction(title: "Setting", style: .default)
154− { [weak self] (_) in
155− self?.onSettings?()
156− }
157−
172+
158173 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
159174
160− let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
161− { [weak self]
162− (_) in
163− self?.logOut?()
175+
176+ if idProfile == DataStorage.standard.getUserId() {
177+ let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
178+ { [weak self] (_) in
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
205+
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)
164238 }
165239
166− optionMenu.addAction(channelAction)
167− optionMenu.addAction(settingsAction)
168− optionMenu.addAction(logoutAction)
169240 optionMenu.addAction(cancelAction)
170−
171241 self.present(optionMenu, animated: true, completion: nil)
172242 }
173243
@@ -197,6 +267,7 @@ class ProfileViewController: UIViewController
197267 func changeToBasicInfo(){
198268 tableView.delegate = basicInfo
199269 tableView.dataSource = basicInfo
270+ basicInfo.userInfo = self.user
200271 tableView.reloadData()
201272 }
202273}
GDproject/DataStorage.swift+8
@@ -37,6 +37,13 @@ class DataStorage{
3737 return UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
3838 }
3939
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+ }
4047 /**
4148 Function to determine is user logged in already or not
4249 */
@@ -49,4 +56,5 @@ class DataStorage{
4956enum UserDefaultsKeys: String{
5057 case loggedIn
5158 case id
59+ case email
5260}
GDproject/Extentions.swift+30
@@ -77,3 +77,33 @@ extension String {
7777 return timeStamp
7878 }
7979}
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/Model.swift+315−23
@@ -10,29 +10,56 @@ import Foundation
1010import UIKit
1111import Alamofire
1212
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+
1329class Model{
1430
1531 static let invalidTocken = 498
1632
17− static var hashTagTree: CompletionTree?
33+ static var hashTagTree: CompletionTree?
1834
1935 private static var isValidTocken: ((Int)->())? = { responce in
2036 print(responce)
2137 if responce == invalidTocken {
38+
2239 DataStorage.standard.setIsLoggedIn(value: false, with: 0)
2340 (UIApplication.shared.delegate as! AppDelegate).relaunch()
41+
42+ Model.logout {
43+ print("Logout Is Successful")
44+ }
2445 }
2546 }
2647
2748 private static let baseUrl = "https://valera-denis.herokuapp.com"
2849 static let decoder = JSONDecoder()
29−
50+
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")!
3055 static let authenticationURL = URL(string:"\(baseUrl)/authentication/login")!
56+ static let logOutURL = URL(string:"\(baseUrl)/authentication/logout")!
3157 static let postsLastURL = URL(string:"\(baseUrl)/posts/last")!
3258 static let postsForUserURL = URL(string:"\(baseUrl)/posts/forUser")!
3359 static let postsPublishURL = URL(string:"\(baseUrl)/posts/publish")!
3460 static let usersURL = URL(string:"\(baseUrl)/users")!
3561 static let usersAllURL = URL(string:"\(baseUrl)/users/all")!
62+ static let usersUpdateURL = URL(string:"\(baseUrl)/users/update")!
3663 static let channelsGetURL = URL(string: "\(baseUrl)/channels/get")!
3764 static let channelsUpdateURL = URL(string: "\(baseUrl)/channels/update")!
3865 static let channelsListURL = URL(string: "\(baseUrl)/channels")!
@@ -49,6 +76,7 @@ class Model{
4976 static let messagesGetGroupChatURL = URL(string: "\(baseUrl)/messages/get/groupChat")! //r
5077 static let messagesSendURL = URL(string: "\(baseUrl)/messages/send")!
5178 static let messagesGetUserChatURL = URL(string: "\(baseUrl)/messages/get/userChat")!
79+ static let facultySearchURL = URL(string: "\(baseUrl)/faculty/search")!
5280
5381
5482 struct QueryPosts<T: Codable>: Codable {
@@ -120,6 +148,8 @@ class Model{
120148 var lastName: String
121149 var firstName: String
122150 var id: Int
151+ var faculty: Faculty
152+ var email: String
123153
124154 func fullName() -> String {
125155 return "\(firstName) \(lastName)"
@@ -183,24 +213,108 @@ class Model{
183213 }
184214 }
185215
186− static func authenticate(with id: Int, completion: @escaping ((Bool)->())) {
216+ struct AuthStatus: Codable {
217+ var userStatus: String
187218
188− let json: [String:Any] = ["authenticationId" : id]
189− let jsonData = try? JSONSerialization.data(withJSONObject: json)
219+ init(){
220+ userStatus = "invalid"
221+ }
222+ }
223+
224+ static func logout(completion: @escaping (()->())){
225+ var request = URLRequest(url: logOutURL)
226+ request.httpMethod = "POST"
227+
228+ AF.request(request).response { (responce) in
229+ isValidTocken?(responce.response?.statusCode ?? 498)
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)
190258
191− var request = URLRequest(url: authenticationURL)
192259 request.httpMethod = "POST"
260+ request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
193261
194− // insert json data to the request
195− request.httpBody = jsonData
262+ AF.request(request).response { (responce) in
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)
196287 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
197288
198289 AF.request(request).response { (responce) in
199290
200− guard let realResponse = responce.response, realResponse.statusCode == 200 else
201− {
202− print("Not a 200 response")
291+ guard let statusCode = responce.response?.statusCode else { completion(false); return }
292+ isValidTocken?(statusCode)
293+
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 {
203302 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 {
204318 return
205319 }
206320
@@ -210,14 +324,45 @@ class Model{
210324 return
211325 }
212326
213− let fields = realResponse.allHeaderFields as? [String :String]
327+ DataStorage.standard.setIsLoggedIn(value: true, with: personId)
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
214346
215− let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields!, for: realResponse.url!)
347+ guard let realResponse = response.response, realResponse.statusCode == 200 else
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 }
216356
217− HTTPCookieStorage.shared.setCookie(cookies[0])
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])
363+ }
218364
219− DataStorage.standard.setIsLoggedIn(value: true, with: personId)
220− completion(true)
365+ completion(res)
221366 }
222367 }
223368
@@ -267,6 +412,10 @@ class Model{
267412
268413 isValidTocken?(response.response?.statusCode ?? 498)
269414
415+ if let code = response.response?.statusCode, code == 498 {
416+ return
417+ }
418+
270419 guard let json = response.data else { return }
271420
272421 guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { print("no")
@@ -278,7 +427,7 @@ class Model{
278427 }
279428
280429
281− static func createAndPublish(body: [Attachments], tags: [String]){
430+ static func createAndPublish(body: [Attachments], tags: [String], completion: @escaping ((ResultR)->())){
282431 let jsonUpd = CreatedPost(body: body, tags: tags)
283432 var request = URLRequest(url: postsPublishURL)
284433
@@ -292,6 +441,18 @@ class Model{
292441 (response) in
293442
294443 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+ }
295456 }
296457 }
297458
@@ -317,6 +478,10 @@ class Model{
317478
318479 isValidTocken?(response.response?.statusCode ?? 498)
319480
481+ if let code = response.response?.statusCode, code == 498 {
482+ return
483+ }
484+
320485 guard let json = response.data else { return }
321486
322487 guard let newPost = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
@@ -329,7 +494,7 @@ class Model{
329494
330495 static func getUsers(for ids: [Int], completion: @escaping (([Int:Users])->())){
331496 let json = "\(Set(ids))"
332− print(json)
497+
333498 var request = URLRequest(url: usersURL)
334499
335500 request.httpMethod = "POST"
@@ -343,11 +508,16 @@ class Model{
343508
344509 isValidTocken?(response.response?.statusCode ?? 498)
345510
511+ if let code = response.response?.statusCode, code == 498 {
512+ return
513+ }
514+
346515 guard let json = response.data else { return }
347516
348517 guard let users = try? decoder.decode([Users].self, from: json) else { return }
349518
350519 var dict: [Int:Users] = [:]
520+
351521 users.forEach({ (user) in
352522 dict[user.id] = user
353523 })
@@ -374,6 +544,9 @@ class Model{
374544
375545 isValidTocken?(response.response?.statusCode ?? 498)
376546
547+ if let code = response.response?.statusCode, code == 498 {
548+ return
549+ }
377550
378551 guard let json = response.data else { return }
379552
@@ -385,7 +558,7 @@ class Model{
385558 }
386559
387560
388− static func createChannel(with channel: Channels) {
561+ static func createChannel(with channel: Channels, completion: @escaping ((ResultR)->())) {
389562
390563 var request = URLRequest(url: channelsCreateURL)
391564 request.httpMethod = "POST"
@@ -396,6 +569,13 @@ class Model{
396569 (response) in
397570
398571 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)
399579 }
400580
401581 }
@@ -408,6 +588,9 @@ class Model{
408588 AF.request(request).responseJSON { (response) in
409589
410590 isValidTocken?(response.response?.statusCode ?? 498)
591+ if let code = response.response?.statusCode, code == 498 {
592+ return
593+ }
411594
412595 guard let json = response.data else { return }
413596
@@ -426,6 +609,9 @@ class Model{
426609
427610 AF.request(request).response { (response) in
428611 isValidTocken?(response.response?.statusCode ?? 498)
612+ if let code = response.response?.statusCode, code == 498 {
613+ return
614+ }
429615 }
430616 completion()
431617 }
@@ -441,6 +627,9 @@ class Model{
441627 (response) in
442628
443629 isValidTocken?(response.response?.statusCode ?? 498)
630+ if let code = response.response?.statusCode, code == 498 {
631+ return
632+ }
444633 }
445634 }
446635
@@ -463,6 +652,9 @@ class Model{
463652 }
464653
465654 isValidTocken?(response.response?.statusCode ?? 498)
655+ if let code = response.response?.statusCode, code == 498 {
656+ return
657+ }
466658 }
467659 }
468660
@@ -538,12 +730,13 @@ class Model{
538730 (response) in
539731
540732 isValidTocken?(response.response?.statusCode ?? 498)
733+ if let code = response.response?.statusCode, code == 498 {
734+ return
735+ }
541736
542737 guard let json = response.data else { return }
543738
544739 guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
545−
546− // idUser = newQueery.users
547740 completion((newQueery.users, newQueery.response))
548741 }
549742 }
@@ -553,6 +746,9 @@ class Model{
553746 AF.request(URLRequest(url: hashTagTreeURL)).responseJSON {
554747 (response) in
555748 isValidTocken?(response.response?.statusCode ?? 498)
749+ if let code = response.response?.statusCode, code == 498 {
750+ return
751+ }
556752 guard let json = response.data else { return }
557753 guard let tree = try? decoder.decode(CompletionTree.self, from: json) else { return }
558754 completion(tree)
@@ -570,6 +766,10 @@ class Model{
570766 AF.request(request).responseJSON { response in
571767 isValidTocken?(response.response?.statusCode ?? 498)
572768
769+ if let code = response.response?.statusCode, code == 498 {
770+ return
771+ }
772+
573773 guard let json = response.data else { return }
574774 let dialogs = try! decoder.decode(QueryPosts<Dialog>.self, from: json)
575775
@@ -741,6 +941,9 @@ class Model{
741941 AF.request(request).response { (response) in
742942
743943 isValidTocken?(response.response?.statusCode ?? 498)
944+ if let code = response.response?.statusCode, code == 498 {
945+ return
946+ }
744947
745948 guard let json = response.data else { return }
746949 let stringInt = String.init(data: json, encoding: String.Encoding.utf8)
@@ -750,7 +953,7 @@ class Model{
750953 }
751954 }
752955
753− static func getMessagesFor(typeOfChat: Model.Dialog, chat id: Int, exclusiveFrom: Int? = nil, limit l: Int = 10, direction: String = "backward", completion: @escaping (([LastMessage])->()))
956+ static func getMessagesFor(typeOfChat: Model.Dialog, chat id: Int, exclusiveFrom: Int? = nil, limit l: Int = 25, direction: String = "backward", completion: @escaping (([LastMessage])->()))
754957 {
755958 let req = GeneralRequest<Int>(direction: direction, limit: l, exclusiveFrom: exclusiveFrom, request: id)
756959 var request: URLRequest?
@@ -769,6 +972,9 @@ class Model{
769972 AF.request(request!).response { (response) in
770973
771974 isValidTocken?(response.response?.statusCode ?? 498)
975+ if let code = response.response?.statusCode, code == 498 {
976+ return
977+ }
772978
773979 guard let json = response.data else { return }
774980 guard let messages = try? decoder.decode([LastMessage].self, from: json) else { return }
@@ -786,6 +992,10 @@ class Model{
786992
787993 AF.request(request).response { (response) in
788994 isValidTocken?(response.response?.statusCode ?? 498)
995+
996+ if let code = response.response?.statusCode, code == 498 {
997+ return
998+ }
789999 }
7901000
7911001 completion()
@@ -800,6 +1010,10 @@ class Model{
8001010
8011011 AF.request(request).response { (response) in
8021012 isValidTocken?(response.response?.statusCode ?? 498)
1013+
1014+ if let code = response.response?.statusCode, code == 498 {
1015+ return
1016+ }
8031017 }
8041018
8051019 // completion()
@@ -842,7 +1056,7 @@ class Model{
8421056 }
8431057 }
8441058
845− static func sendMessage(message: SendMessage, completion: @escaping (()->())){
1059+ static func sendMessage(message: SendMessage, completion: @escaping ((ResultR)->())){
8461060
8471061 var request = URLRequest(url: messagesSendURL)
8481062 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
@@ -852,6 +1066,84 @@ class Model{
8521066 AF.request(request).response { (response) in
8531067 isValidTocken?(response.response?.statusCode ?? 498)
8541068
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+
8551147 completion()
8561148 }
8571149 }