git.iko.soy/dashared/GDproject
on 478eb78 help sign in
70 files changed+883−6305
since splitsnapshots
unifiedsplit
Cartfile+1−5 GDproject.xcodeproj/project.pbxproj+41−214 GDproject.xcodeproj/xcshareddata/xcschemes/GDproject.xcscheme−106 GDproject/Base.lproj/Main.storyboard+88−709 GDproject/Constants.swift−28 GDproject/Controller/ News and channels/AddToChannelVC.swift−132 GDproject/Controller/ News and channels/ChannelController.swift+60−159 GDproject/Controller/ News and channels/ChannelListController.swift+58−74 GDproject/Controller/ News and channels/ChannelViewController.swift−208 GDproject/Controller/ News and channels/FullPostController.swift+25−21 GDproject/Controller/ News and channels/NewPostViewController.swift+41−131 GDproject/Controller/ News and channels/NewsController.swift+183−96 GDproject/Controller/ News and channels/NewsVC.swift+50−99 GDproject/Controller/ News and channels/PostViewCell.swift+38−63 GDproject/Controller/ News and channels/SimplifiedChannelsList.swift−94 GDproject/Controller/ News and channels/TaggsSelectionViewController.swift−106 GDproject/Controller/ News and channels/TagsSuggestionController.swift−52 GDproject/Controller/Coordinators/ApplicationCoordinator.swift−69 GDproject/Controller/Coordinators/BaseCoordinator.swift−47 GDproject/Controller/Coordinators/ChannelsCoordinator.swift−139 GDproject/Controller/Coordinators/LogInCoordinator.swift−70 GDproject/Controller/Coordinators/MessagesCoordinator.swift−87 GDproject/Controller/Coordinators/ProfileCoordinator.swift−60 GDproject/Controller/Coordinators/TabbarController.swift−50 GDproject/Controller/Coordinators/TabbarCoordinator.swift−68 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/LogInViewController.swift−155 GDproject/Controller/Log In/RegisterTableViewController.swift−198 GDproject/Controller/LogInViewController.swift+138 GDproject/Controller/Messages/ChatInfoViewController.swift−308 GDproject/Controller/Messages/Dialog/DialogCell.swift−132 GDproject/Controller/Messages/Dialog/DialogViewController.swift−340 GDproject/Controller/Messages/MessageViewCell.swift−38 GDproject/Controller/Messages/MessagesViewController.swift−181 GDproject/Controller/Messages/PeopleToWriteViewController.swift−67 GDproject/Controller/Profile/BasicInfoController.swift+12−16 GDproject/Controller/Profile/InfoCell.swift+1−2 GDproject/Controller/Profile/ProfileViewController.swift+41−171 GDproject/DataStorage.swift+8−23 GDproject/Extentions.swift−73 GDproject/Simple model/Channel.swift+3−10 GDproject/Simple model/CompletionTree.swift−44 GDproject/Simple model/Model.swift−1150 GDproject/Simple model/Post.swift+26 GDproject/Simple model/User.swift+41 GDproject/Supporting files/AppDelegate.swift+28−20 GDproject/Supporting files/Assets.xcassets/1.imageset/1.pdf GDproject/Supporting files/Assets.xcassets/1.imageset/Contents.json−25 GDproject/Supporting files/Assets.xcassets/2.imageset/2.pdf GDproject/Supporting files/Assets.xcassets/2.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/3.imageset/3.pdf GDproject/Supporting files/Assets.xcassets/3.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/4.imageset/4.pdf GDproject/Supporting files/Assets.xcassets/4.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/42.imageset/42.png GDproject/Supporting files/Assets.xcassets/42.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/5.imageset/5.pdf GDproject/Supporting files/Assets.xcassets/5.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/5051.imageset/5051.png GDproject/Supporting files/Assets.xcassets/5051.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/69.imageset/69.png GDproject/Supporting files/Assets.xcassets/69.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/9.imageset/9.png GDproject/Supporting files/Assets.xcassets/9.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/chat.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/chat.imageset/chat.pdf GDproject/Supporting files/Assets.xcassets/share.imageset/Contents.json−21 GDproject/Supporting files/Assets.xcassets/share.imageset/share.png
Cartfile+1−5
@@ -2,8 +2,4 @@ github "robb/Cartography"
22github "ivanbruel/MarkdownKit"
33github "roberthein/TinyConstraints"
44github "macteo/Marklight"
5−github "Alamofire/Alamofire" "5.0.0-beta.5"
6−github "52inc/Pulley"
7−github "HeroTransitions/Hero"
8−github "ReactiveCocoa/ReactiveCocoa" ~> 9.0
9−github "ZaidSA/TaggerKit" "bb826a7"
5+github "ElaWorkshop/TagListView"
GDproject.xcodeproj/project.pbxproj+41−214
@@ -7,37 +7,12 @@
77 objects = {
88
99/* Begin PBXBuildFile section */
10− 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */; };
11− 121A8972226B1EAC005EE599 /* TagsSuggestionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */; };
12− 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */; };
13− 123589FD22899339002F8028 /* MessageViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123589FC22899339002F8028 /* MessageViewCell.swift */; };
1410 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
1511 123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
16− 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 */; };
2112 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57C22171D2A008A3575 /* ProfileViewController.swift */; };
2213 125BD57F22171D73008A3575 /* Extentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57E22171D73008A3575 /* Extentions.swift */; };
2314 125BD5812217314A008A3575 /* NewsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD5802217314A008A3575 /* NewsVC.swift */; };
24− 1261BB93227B364C003898CF /* ChannelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB92227B364C003898CF /* ChannelViewController.swift */; };
25− 1261BB95227B3991003898CF /* AddToChannelVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB94227B3991003898CF /* AddToChannelVC.swift */; };
26− 1261BB9E227B793D003898CF /* ChatInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB9D227B793D003898CF /* ChatInfoViewController.swift */; };
27− 12758257227F1401001F291F /* DialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12758256227F1401001F291F /* DialogViewController.swift */; };
2815 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1288B5CD221F1158002BE6B1 /* DataStorage.swift */; };
29− 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */; };
30− 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */; };
31− 129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320032279B4270035C7B3 /* MessagesViewController.swift */; };
32− 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320062279B5690035C7B3 /* MessagesCoordinator.swift */; };
33− 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */; };
34− 1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1293200C2279D7310035C7B3 /* CompletionTree.swift */; };
35− 1298810B227F13840032ACA3 /* DialogCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1298810A227F13840032ACA3 /* DialogCell.swift */; };
36− 12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */; };
37− 12BA4B9D224101E700DF93D7 /* BaseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */; };
38− 12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */; };
39− 12CE7D6F227B94B10024B6E8 /* TaggerKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */; };
40− 12CE7D71227B94B50024B6E8 /* TaggerKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4116 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D132221C321600B35452 /* ChannelListController.swift */; };
4217 12D7D135221C42B700B35452 /* ChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D134221C42B700B35452 /* ChannelController.swift */; };
4318 12D7D137221D78E800B35452 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D136221D78E800B35452 /* Channel.swift */; };
@@ -51,54 +26,37 @@
5126 12E36DA1221424EA006FCDD7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36D9F221424EA006FCDD7 /* Main.storyboard */; };
5227 12E36DA3221424ED006FCDD7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA2221424ED006FCDD7 /* Assets.xcassets */; };
5328 12E36DA6221424ED006FCDD7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA4221424ED006FCDD7 /* LaunchScreen.storyboard */; };
29+ 12E36DAF22143D40006FCDD7 /* Cartography.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DAE22143D40006FCDD7 /* Cartography.framework */; };
30+ 12E36DB322143D4E006FCDD7 /* Marklight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB222143D4E006FCDD7 /* Marklight.framework */; };
31+ 12E36DB522143D54006FCDD7 /* TinyConstraints.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */; };
5432 12E36DB72214400A006FCDD7 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB62214400A006FCDD7 /* Post.swift */; };
33+ 12E36DB922144016006FCDD7 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB822144016006FCDD7 /* User.swift */; };
34+ 12E36DBD221441D5006FCDD7 /* TinyConstraints.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
35+ 12E36DC0221441DB006FCDD7 /* Marklight.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB222143D4E006FCDD7 /* Marklight.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
36+ 12E36DC2221441E1006FCDD7 /* MarkdownKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
37+ 12E36DC4221441EA006FCDD7 /* Cartography.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DAE22143D40006FCDD7 /* Cartography.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5538 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DC922144635006FCDD7 /* NewPostViewController.swift */; };
5639 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCB22144725006FCDD7 /* PostViewCell.swift */; };
5740 12E36DCE22144756006FCDD7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCD22144756006FCDD7 /* Constants.swift */; };
5841 12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DD022148122006FCDD7 /* FullPostController.swift */; };
5942 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DD422156559006FCDD7 /* MyStackView.swift */; };
60− 12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F3D6AF224106F700A69214 /* TabbarController.swift */; };
61− 12F3D6B22241097B00A69214 /* ProfileCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F3D6B12241097B00A69214 /* ProfileCoordinator.swift */; };
62− 12FDAC7C226B5E2900995B4E /* Marklight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC75226B5E2800995B4E /* Marklight.framework */; };
63− 12FDAC7D226B5E2900995B4E /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC76226B5E2800995B4E /* Result.framework */; };
64− 12FDAC7E226B5E2900995B4E /* Cartography.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC77226B5E2900995B4E /* Cartography.framework */; };
65− 12FDAC81226B5E2900995B4E /* MarkdownKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */; };
66− 12FDAC84226B5E3700995B4E /* Alamofire.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC79226B5E2900995B4E /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
67− 12FDAC88226B5E4800995B4E /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC79226B5E2900995B4E /* Alamofire.framework */; };
68− 12FDAC8A226B5E4B00995B4E /* Cartography.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC77226B5E2900995B4E /* Cartography.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
69− 12FDAC8B226B5E4E00995B4E /* Hero.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC78226B5E2900995B4E /* Hero.framework */; };
70− 12FDAC8C226B5E4E00995B4E /* Hero.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC78226B5E2900995B4E /* Hero.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
71− 12FDAC8E226B5E5000995B4E /* MarkdownKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
72− 12FDAC90226B5E5200995B4E /* Marklight.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC75226B5E2800995B4E /* Marklight.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
73− 12FDAC91226B5E5400995B4E /* Pulley.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC7B226B5E2900995B4E /* Pulley.framework */; };
74− 12FDAC92226B5E5400995B4E /* Pulley.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC7B226B5E2900995B4E /* Pulley.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
75− 12FDAC94226B5E5600995B4E /* Result.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC76226B5E2800995B4E /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
76− 12FDAC96226B61C400995B4E /* TinyConstraints.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC95226B61C400995B4E /* TinyConstraints.framework */; };
77− 12FDAC98226B61CB00995B4E /* TinyConstraints.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC95226B61C400995B4E /* TinyConstraints.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
78− 12FDAC9B226B652C00995B4E /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC99226B652400995B4E /* ReactiveSwift.framework */; };
79− 12FDAC9C226B652C00995B4E /* ReactiveSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC99226B652400995B4E /* ReactiveSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
80− 12FDAC9F226B9E7C00995B4E /* ReactiveCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */; };
81− 12FDACA0226B9E7C00995B4E /* ReactiveCocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
43+ 12E36DD8221594A9006FCDD7 /* TagListView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DD622159493006FCDD7 /* TagListView.framework */; };
44+ 12E36DD9221594A9006FCDD7 /* TagListView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DD622159493006FCDD7 /* TagListView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
45+ 12E36DDB221594B1006FCDD7 /* MarkdownKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */; };
8246/* End PBXBuildFile section */
8347
8448/* Begin PBXCopyFilesBuildPhase section */
85− 12FDAC85226B5E3700995B4E /* Embed Frameworks */ = {
49+ 12E36DBE221441D5006FCDD7 /* Embed Frameworks */ = {
8650 isa = PBXCopyFilesBuildPhase;
8751 buildActionMask = 2147483647;
8852 dstPath = "";
8953 dstSubfolderSpec = 10;
9054 files = (
91− 12FDAC8E226B5E5000995B4E /* MarkdownKit.framework in Embed Frameworks */,
92− 12FDAC98226B61CB00995B4E /* TinyConstraints.framework in Embed Frameworks */,
93− 12FDAC94226B5E5600995B4E /* Result.framework in Embed Frameworks */,
94− 12FDAC84226B5E3700995B4E /* Alamofire.framework in Embed Frameworks */,
95− 12FDAC8A226B5E4B00995B4E /* Cartography.framework in Embed Frameworks */,
96− 12FDAC9C226B652C00995B4E /* ReactiveSwift.framework in Embed Frameworks */,
97− 12FDAC92226B5E5400995B4E /* Pulley.framework in Embed Frameworks */,
98− 12FDAC8C226B5E4E00995B4E /* Hero.framework in Embed Frameworks */,
99− 12FDAC90226B5E5200995B4E /* Marklight.framework in Embed Frameworks */,
100− 12CE7D71227B94B50024B6E8 /* TaggerKit.framework in Embed Frameworks */,
101− 12FDACA0226B9E7C00995B4E /* ReactiveCocoa.framework in Embed Frameworks */,
55+ 12E36DC0221441DB006FCDD7 /* Marklight.framework in Embed Frameworks */,
56+ 12E36DC4221441EA006FCDD7 /* Cartography.framework in Embed Frameworks */,
57+ 12E36DD9221594A9006FCDD7 /* TagListView.framework in Embed Frameworks */,
58+ 12E36DBD221441D5006FCDD7 /* TinyConstraints.framework in Embed Frameworks */,
59+ 12E36DC2221441E1006FCDD7 /* MarkdownKit.framework in Embed Frameworks */,
10260 );
10361 name = "Embed Frameworks";
10462 runOnlyForDeploymentPostprocessing = 0;
@@ -106,36 +64,12 @@
10664/* End PBXCopyFilesBuildPhase section */
10765
10866/* Begin PBXFileReference section */
109− 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplifiedChannelsList.swift; sourceTree = "<group>"; };
110− 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsSuggestionController.swift; sourceTree = "<group>"; };
111− 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaggsSelectionViewController.swift; sourceTree = "<group>"; };
112− 123589FC22899339002F8028 /* MessageViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewCell.swift; sourceTree = "<group>"; };
11367 123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
11468 123E37A6221F1DD700F6E42A /* MainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
115− 124CC7022221C00C009DF531 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
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>"; };
12069 125BD57C22171D2A008A3575 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
12170 125BD57E22171D73008A3575 /* Extentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extentions.swift; sourceTree = "<group>"; };
12271 125BD5802217314A008A3575 /* NewsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsVC.swift; sourceTree = "<group>"; };
123− 1261BB92227B364C003898CF /* ChannelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelViewController.swift; sourceTree = "<group>"; };
124− 1261BB94227B3991003898CF /* AddToChannelVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddToChannelVC.swift; sourceTree = "<group>"; };
125− 1261BB9D227B793D003898CF /* ChatInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoViewController.swift; sourceTree = "<group>"; };
126− 12758256227F1401001F291F /* DialogViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DialogViewController.swift; sourceTree = "<group>"; };
12772 1288B5CD221F1158002BE6B1 /* DataStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStorage.swift; sourceTree = "<group>"; };
128− 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelsCoordinator.swift; sourceTree = "<group>"; };
129− 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbarCoordinator.swift; sourceTree = "<group>"; };
130− 129320032279B4270035C7B3 /* MessagesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = "<group>"; };
131− 129320062279B5690035C7B3 /* MessagesCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesCoordinator.swift; sourceTree = "<group>"; };
132− 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PeopleToWriteViewController.swift; path = GDproject/Controller/Messages/PeopleToWriteViewController.swift; sourceTree = SOURCE_ROOT; };
133− 1293200C2279D7310035C7B3 /* CompletionTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionTree.swift; sourceTree = "<group>"; };
134− 1298810A227F13840032ACA3 /* DialogCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialogCell.swift; sourceTree = "<group>"; };
135− 12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationCoordinator.swift; sourceTree = "<group>"; };
136− 12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCoordinator.swift; sourceTree = "<group>"; };
137− 12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInCoordinator.swift; sourceTree = "<group>"; };
138− 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TaggerKit.framework; path = Carthage/Build/iOS/TaggerKit.framework; sourceTree = "<group>"; };
13973 12D7D132221C321600B35452 /* ChannelListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelListController.swift; sourceTree = "<group>"; };
14074 12D7D134221C42B700B35452 /* ChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelController.swift; sourceTree = "<group>"; };
14175 12D7D136221D78E800B35452 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
@@ -151,24 +85,18 @@
15185 12E36DA2221424ED006FCDD7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
15286 12E36DA5221424ED006FCDD7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
15387 12E36DA7221424ED006FCDD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
88+ 12E36DAE22143D40006FCDD7 /* Cartography.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cartography.framework; path = Carthage/Build/iOS/Cartography.framework; sourceTree = "<group>"; };
89+ 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MarkdownKit.framework; path = Carthage/Build/iOS/MarkdownKit.framework; sourceTree = "<group>"; };
90+ 12E36DB222143D4E006FCDD7 /* Marklight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Marklight.framework; path = Carthage/Build/iOS/Marklight.framework; sourceTree = "<group>"; };
91+ 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TinyConstraints.framework; path = Carthage/Build/iOS/TinyConstraints.framework; sourceTree = "<group>"; };
15492 12E36DB62214400A006FCDD7 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
93+ 12E36DB822144016006FCDD7 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
15594 12E36DC922144635006FCDD7 /* NewPostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPostViewController.swift; sourceTree = "<group>"; };
15695 12E36DCB22144725006FCDD7 /* PostViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewCell.swift; sourceTree = "<group>"; };
15796 12E36DCD22144756006FCDD7 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
15897 12E36DD022148122006FCDD7 /* FullPostController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullPostController.swift; sourceTree = "<group>"; };
15998 12E36DD422156559006FCDD7 /* MyStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyStackView.swift; sourceTree = "<group>"; };
160− 12F3D6AF224106F700A69214 /* TabbarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbarController.swift; sourceTree = "<group>"; };
161− 12F3D6B12241097B00A69214 /* ProfileCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileCoordinator.swift; sourceTree = "<group>"; };
162− 12FDAC75226B5E2800995B4E /* Marklight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Marklight.framework; path = Carthage/Build/iOS/Marklight.framework; sourceTree = "<group>"; };
163− 12FDAC76226B5E2800995B4E /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = "<group>"; };
164− 12FDAC77226B5E2900995B4E /* Cartography.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cartography.framework; path = Carthage/Build/iOS/Cartography.framework; sourceTree = "<group>"; };
165− 12FDAC78226B5E2900995B4E /* Hero.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Hero.framework; path = Carthage/Build/iOS/Hero.framework; sourceTree = "<group>"; };
166− 12FDAC79226B5E2900995B4E /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = "<group>"; };
167− 12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MarkdownKit.framework; path = Carthage/Build/iOS/MarkdownKit.framework; sourceTree = "<group>"; };
168− 12FDAC7B226B5E2900995B4E /* Pulley.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pulley.framework; path = Carthage/Build/iOS/Pulley.framework; sourceTree = "<group>"; };
169− 12FDAC95226B61C400995B4E /* TinyConstraints.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TinyConstraints.framework; path = Carthage/Build/iOS/TinyConstraints.framework; sourceTree = "<group>"; };
170− 12FDAC99226B652400995B4E /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = "<group>"; };
171− 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveCocoa.framework; path = Carthage/Build/iOS/ReactiveCocoa.framework; sourceTree = "<group>"; };
99+ 12E36DD622159493006FCDD7 /* TagListView.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TagListView.framework; path = Carthage/Build/iOS/TagListView.framework; sourceTree = "<group>"; };
172100/* End PBXFileReference section */
173101
174102/* Begin PBXFrameworksBuildPhase section */
@@ -176,17 +104,11 @@
176104 isa = PBXFrameworksBuildPhase;
177105 buildActionMask = 2147483647;
178106 files = (
179− 12FDAC7C226B5E2900995B4E /* Marklight.framework in Frameworks */,
180− 12FDAC96226B61C400995B4E /* TinyConstraints.framework in Frameworks */,
181− 12FDAC91226B5E5400995B4E /* Pulley.framework in Frameworks */,
182− 12FDAC9F226B9E7C00995B4E /* ReactiveCocoa.framework in Frameworks */,
183− 12FDAC88226B5E4800995B4E /* Alamofire.framework in Frameworks */,
184− 12FDAC81226B5E2900995B4E /* MarkdownKit.framework in Frameworks */,
185− 12FDAC7D226B5E2900995B4E /* Result.framework in Frameworks */,
186− 12FDAC9B226B652C00995B4E /* ReactiveSwift.framework in Frameworks */,
187− 12FDAC7E226B5E2900995B4E /* Cartography.framework in Frameworks */,
188− 12CE7D6F227B94B10024B6E8 /* TaggerKit.framework in Frameworks */,
189− 12FDAC8B226B5E4E00995B4E /* Hero.framework in Frameworks */,
107+ 12E36DB522143D54006FCDD7 /* TinyConstraints.framework in Frameworks */,
108+ 12E36DDB221594B1006FCDD7 /* MarkdownKit.framework in Frameworks */,
109+ 12E36DD8221594A9006FCDD7 /* TagListView.framework in Frameworks */,
110+ 12E36DAF22143D40006FCDD7 /* Cartography.framework in Frameworks */,
111+ 12E36DB322143D4E006FCDD7 /* Marklight.framework in Frameworks */,
190112 );
191113 runOnlyForDeploymentPostprocessing = 0;
192114 };
@@ -206,68 +128,14 @@
206128 path = Profile;
207129 sourceTree = "<group>";
208130 };
209− 1291BE32222154C3009D3F23 /* Coordinators */ = {
210− isa = PBXGroup;
211− children = (
212− 12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */,
213− 129320062279B5690035C7B3 /* MessagesCoordinator.swift */,
214− 12F3D6AF224106F700A69214 /* TabbarController.swift */,
215− 12F3D6B12241097B00A69214 /* ProfileCoordinator.swift */,
216− 12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */,
217− 12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */,
218− 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */,
219− 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */,
220− );
221− path = Coordinators;
222− sourceTree = "<group>";
223− };
224− 1291BE3722218DC4009D3F23 /* Log In */ = {
225− isa = PBXGroup;
226− children = (
227− 125A9A912286100800513E2A /* FacultyTableViewController.swift */,
228− 125A9A8F228609C500513E2A /* InititalsViewCell.swift */,
229− 125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */,
230− 125A9A892285C3DA00513E2A /* CodeViewController.swift */,
231− 123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
232− );
233− path = "Log In";
234− sourceTree = "<group>";
235− };
236− 129320052279B4300035C7B3 /* Messages */ = {
237− isa = PBXGroup;
238− children = (
239− 1261BB9D227B793D003898CF /* ChatInfoViewController.swift */,
240− 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */,
241− 1298810C227F138C0032ACA3 /* Dialog */,
242− 129320032279B4270035C7B3 /* MessagesViewController.swift */,
243− 123589FC22899339002F8028 /* MessageViewCell.swift */,
244− );
245− path = Messages;
246− sourceTree = "<group>";
247− };
248− 1298810C227F138C0032ACA3 /* Dialog */ = {
249− isa = PBXGroup;
250− children = (
251− 12758256227F1401001F291F /* DialogViewController.swift */,
252− 1298810A227F13840032ACA3 /* DialogCell.swift */,
253− );
254− path = Dialog;
255− sourceTree = "<group>";
256− };
257131 12E36D8F221424EA006FCDD7 = {
258132 isa = PBXGroup;
259133 children = (
260− 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */,
261− 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */,
262− 12FDAC99226B652400995B4E /* ReactiveSwift.framework */,
263− 12FDAC95226B61C400995B4E /* TinyConstraints.framework */,
264− 12FDAC79226B5E2900995B4E /* Alamofire.framework */,
265− 12FDAC77226B5E2900995B4E /* Cartography.framework */,
266− 12FDAC78226B5E2900995B4E /* Hero.framework */,
267− 12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */,
268− 12FDAC75226B5E2800995B4E /* Marklight.framework */,
269− 12FDAC7B226B5E2900995B4E /* Pulley.framework */,
270− 12FDAC76226B5E2800995B4E /* Result.framework */,
134+ 12E36DD622159493006FCDD7 /* TagListView.framework */,
135+ 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */,
136+ 12E36DB222143D4E006FCDD7 /* Marklight.framework */,
137+ 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */,
138+ 12E36DAE22143D40006FCDD7 /* Cartography.framework */,
271139 12E36D9A221424EA006FCDD7 /* GDproject */,
272140 12E36D99221424EA006FCDD7 /* Products */,
273141 12E36DDA221594B1006FCDD7 /* Frameworks */,
@@ -302,10 +170,9 @@
302170 12E36DBA2214401B006FCDD7 /* Simple model */ = {
303171 isa = PBXGroup;
304172 children = (
305− 124CC7022221C00C009DF531 /* Model.swift */,
306− 1293200C2279D7310035C7B3 /* CompletionTree.swift */,
307173 12E36DB62214400A006FCDD7 /* Post.swift */,
308174 12D7D136221D78E800B35452 /* Channel.swift */,
175+ 12E36DB822144016006FCDD7 /* User.swift */,
309176 );
310177 path = "Simple model";
311178 sourceTree = "<group>";
@@ -323,9 +190,7 @@
323190 12E36DCF22145923006FCDD7 /* Controller */ = {
324191 isa = PBXGroup;
325192 children = (
326− 1291BE32222154C3009D3F23 /* Coordinators */,
327− 129320052279B4300035C7B3 /* Messages */,
328− 1291BE3722218DC4009D3F23 /* Log In */,
193+ 123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
329194 1288B5CC221F0EFE002BE6B1 /* Profile */,
330195 12E36DD322156519006FCDD7 /* News and channels */,
331196 );
@@ -335,13 +200,8 @@
335200 12E36DD322156519006FCDD7 /* News and channels */ = {
336201 isa = PBXGroup;
337202 children = (
338− 1261BB92227B364C003898CF /* ChannelViewController.swift */,
339− 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */,
340− 1261BB94227B3991003898CF /* AddToChannelVC.swift */,
341203 12D7D134221C42B700B35452 /* ChannelController.swift */,
342− 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */,
343204 12D7D132221C321600B35452 /* ChannelListController.swift */,
344− 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */,
345205 12E36DC922144635006FCDD7 /* NewPostViewController.swift */,
346206 12E36DD022148122006FCDD7 /* FullPostController.swift */,
347207 12E36D9D221424EA006FCDD7 /* NewsController.swift */,
@@ -368,7 +228,7 @@
368228 12E36D94221424EA006FCDD7 /* Sources */,
369229 12E36D95221424EA006FCDD7 /* Frameworks */,
370230 12E36D96221424EA006FCDD7 /* Resources */,
371− 12FDAC85226B5E3700995B4E /* Embed Frameworks */,
231+ 12E36DBE221441D5006FCDD7 /* Embed Frameworks */,
372232 );
373233 buildRules = (
374234 );
@@ -391,11 +251,6 @@
391251 TargetAttributes = {
392252 12E36D97221424EA006FCDD7 = {
393253 CreatedOnToolsVersion = 10.1;
394− SystemCapabilities = {
395− com.apple.Keychain = {
396− enabled = 0;
397− };
398− };
399254 };
400255 };
401256 };
@@ -435,49 +290,25 @@
435290 isa = PBXSourcesBuildPhase;
436291 buildActionMask = 2147483647;
437292 files = (
438− 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */,
439− 124CC7032221C00C009DF531 /* Model.swift in Sources */,
440− 125A9A90228609C500513E2A /* InititalsViewCell.swift in Sources */,
441− 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */,
442− 12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */,
443293 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
444294 12D7D137221D78E800B35452 /* Channel.swift in Sources */,
445− 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */,
295+ 12E36DB922144016006FCDD7 /* User.swift in Sources */,
446296 125BD5812217314A008A3575 /* NewsVC.swift in Sources */,
447297 12E36DB72214400A006FCDD7 /* Post.swift in Sources */,
448298 12DB7FDF221877160096878E /* InviteViewController.swift in Sources */,
449− 121A8972226B1EAC005EE599 /* TagsSuggestionController.swift in Sources */,
450− 1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */,
451299 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */,
452− 1261BB9E227B793D003898CF /* ChatInfoViewController.swift in Sources */,
453300 12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */,
454− 1298810B227F13840032ACA3 /* DialogCell.swift in Sources */,
455− 125A9A922286100800513E2A /* FacultyTableViewController.swift in Sources */,
456− 125A9A8E2286068A00513E2A /* RegisterTableViewController.swift in Sources */,
457− 123589FD22899339002F8028 /* MessageViewCell.swift in Sources */,
458301 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */,
459302 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */,
460303 125BD57F22171D73008A3575 /* Extentions.swift in Sources */,
461304 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */,
462− 125A9A8A2285C3DA00513E2A /* CodeViewController.swift in Sources */,
463− 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */,
464− 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */,
465− 12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */,
466− 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */,
467305 12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */,
468− 129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */,
469− 12758257227F1401001F291F /* DialogViewController.swift in Sources */,
470306 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */,
471− 12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */,
472− 12F3D6B22241097B00A69214 /* ProfileCoordinator.swift in Sources */,
473307 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */,
474− 1261BB95227B3991003898CF /* AddToChannelVC.swift in Sources */,
475308 12DB7FDB2218590C0096878E /* InfoCell.swift in Sources */,
476309 12DB7FD922181E660096878E /* BasicInfoCell.swift in Sources */,
477− 1261BB93227B364C003898CF /* ChannelViewController.swift in Sources */,
478310 12D7D135221C42B700B35452 /* ChannelController.swift in Sources */,
479311 12E36D9C221424EA006FCDD7 /* AppDelegate.swift in Sources */,
480− 12BA4B9D224101E700DF93D7 /* BaseCoordinator.swift in Sources */,
481312 12DB7FD722181CD20096878E /* BasicInfoController.swift in Sources */,
482313 12E36DCE22144756006FCDD7 /* Constants.swift in Sources */,
483314 12DB7FDD221872F80096878E /* SettingsViewController.swift in Sources */,
@@ -627,7 +458,6 @@
627458 isa = XCBuildConfiguration;
628459 buildSettings = {
629460 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
630− CODE_SIGN_IDENTITY = "iPhone Developer";
631461 CODE_SIGN_STYLE = Automatic;
632462 DEVELOPMENT_TEAM = 9Z6LFGKA9G;
633463 FRAMEWORK_SEARCH_PATHS = (
@@ -639,10 +469,9 @@
639469 "$(inherited)",
640470 "@executable_path/Frameworks",
641471 );
642− PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject.sos;
472+ PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject;
643473 PRODUCT_NAME = "$(TARGET_NAME)";
644− PROVISIONING_PROFILE_SPECIFIER = "";
645− SWIFT_VERSION = 5.0;
474+ SWIFT_VERSION = 4.2;
646475 TARGETED_DEVICE_FAMILY = "1,2";
647476 };
648477 name = Debug;
@@ -651,7 +480,6 @@
651480 isa = XCBuildConfiguration;
652481 buildSettings = {
653482 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
654− CODE_SIGN_IDENTITY = "iPhone Developer";
655483 CODE_SIGN_STYLE = Automatic;
656484 DEVELOPMENT_TEAM = 9Z6LFGKA9G;
657485 FRAMEWORK_SEARCH_PATHS = (
@@ -663,10 +491,9 @@
663491 "$(inherited)",
664492 "@executable_path/Frameworks",
665493 );
666− PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject.sos;
494+ PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject;
667495 PRODUCT_NAME = "$(TARGET_NAME)";
668− PROVISIONING_PROFILE_SPECIFIER = "";
669− SWIFT_VERSION = 5.0;
496+ SWIFT_VERSION = 4.2;
670497 TARGETED_DEVICE_FAMILY = "1,2";
671498 };
672499 name = Release;
GDproject.xcodeproj/xcshareddata/xcschemes/GDproject.xcschemedeleted−106
@@ -1,106 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8"?>
2−<Scheme
3− LastUpgradeVersion = "1010"
4− version = "1.3">
5− <BuildAction
6− parallelizeBuildables = "YES"
7− buildImplicitDependencies = "YES">
8− <BuildActionEntries>
9− <BuildActionEntry
10− buildForTesting = "YES"
11− buildForRunning = "YES"
12− buildForProfiling = "YES"
13− buildForArchiving = "YES"
14− buildForAnalyzing = "YES">
15− <BuildableReference
16− BuildableIdentifier = "primary"
17− BlueprintIdentifier = "12E36D97221424EA006FCDD7"
18− BuildableName = "GDproject.app"
19− BlueprintName = "GDproject"
20− ReferencedContainer = "container:GDproject.xcodeproj">
21− </BuildableReference>
22− </BuildActionEntry>
23− </BuildActionEntries>
24− </BuildAction>
25− <TestAction
26− buildConfiguration = "Debug"
27− selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28− selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29− shouldUseLaunchSchemeArgsEnv = "YES">
30− <Testables>
31− </Testables>
32− <MacroExpansion>
33− <BuildableReference
34− BuildableIdentifier = "primary"
35− BlueprintIdentifier = "12E36D97221424EA006FCDD7"
36− BuildableName = "GDproject.app"
37− BlueprintName = "GDproject"
38− ReferencedContainer = "container:GDproject.xcodeproj">
39− </BuildableReference>
40− </MacroExpansion>
41− <AdditionalOptions>
42− </AdditionalOptions>
43− </TestAction>
44− <LaunchAction
45− buildConfiguration = "Debug"
46− selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47− selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48− launchStyle = "0"
49− useCustomWorkingDirectory = "NO"
50− ignoresPersistentStateOnLaunch = "NO"
51− debugDocumentVersioning = "YES"
52− debugServiceExtension = "internal"
53− allowLocationSimulation = "YES">
54− <BuildableProductRunnable
55− runnableDebuggingMode = "0">
56− <BuildableReference
57− BuildableIdentifier = "primary"
58− BlueprintIdentifier = "12E36D97221424EA006FCDD7"
59− BuildableName = "GDproject.app"
60− BlueprintName = "GDproject"
61− ReferencedContainer = "container:GDproject.xcodeproj">
62− </BuildableReference>
63− </BuildableProductRunnable>
64− <AdditionalOptions>
65− <AdditionalOption
66− key = "MallocStackLogging"
67− value = ""
68− isEnabled = "YES">
69− </AdditionalOption>
70− <AdditionalOption
71− key = "PrefersMallocStackLoggingLite"
72− value = ""
73− isEnabled = "YES">
74− </AdditionalOption>
75− <AdditionalOption
76− key = "MallocScribble"
77− value = ""
78− isEnabled = "YES">
79− </AdditionalOption>
80− </AdditionalOptions>
81− </LaunchAction>
82− <ProfileAction
83− buildConfiguration = "Release"
84− shouldUseLaunchSchemeArgsEnv = "YES"
85− savedToolIdentifier = ""
86− useCustomWorkingDirectory = "NO"
87− debugDocumentVersioning = "YES">
88− <BuildableProductRunnable
89− runnableDebuggingMode = "0">
90− <BuildableReference
91− BuildableIdentifier = "primary"
92− BlueprintIdentifier = "12E36D97221424EA006FCDD7"
93− BuildableName = "GDproject.app"
94− BlueprintName = "GDproject"
95− ReferencedContainer = "container:GDproject.xcodeproj">
96− </BuildableReference>
97− </BuildableProductRunnable>
98− </ProfileAction>
99− <AnalyzeAction
100− buildConfiguration = "Debug">
101− </AnalyzeAction>
102− <ArchiveAction
103− buildConfiguration = "Release"
104− revealArchiveInOrganizer = "YES">
105− </ArchiveAction>
106−</Scheme>
GDproject/Base.lproj/Main.storyboard+88−709
@@ -1,29 +1,46 @@
11<?xml version="1.0" encoding="UTF-8"?>
2−<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="IeP-4W-8LT">
33 <device id="retina4_7" orientation="portrait">
44 <adaptation id="fullscreen"/>
55 </device>
66 <dependencies>
77 <deployment identifier="iOS"/>
8− <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
8+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
99 <capability name="Safe area layout guides" minToolsVersion="9.0"/>
1010 <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
1111 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
1212 </dependencies>
1313 <scenes>
14− <!--Chats-->
15− <scene sceneID="bZ2-fw-XBE">
14+ <!--News Controller-->
15+ <scene sceneID="tne-QT-ifu">
1616 <objects>
17− <navigationController id="gt4-mD-66Q" sceneMemberID="viewController">
18− <tabBarItem key="tabBarItem" title="Chats" image="chat" id="ZPm-j1-3dy"/>
19− <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="XiY-wd-750">
20− <rect key="frame" x="0.0" y="20" width="375" height="44"/>
21− <autoresizingMask key="autoresizingMask"/>
22− </navigationBar>
23− </navigationController>
24− <placeholder placeholderIdentifier="IBFirstResponder" id="4yT-77-90q" userLabel="First Responder" sceneMemberID="firstResponder"/>
17+ <viewController storyboardIdentifier="NewsController" id="BYZ-38-t0r" customClass="NewsController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
18+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
19+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
20+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
21+ <subviews>
22+ <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="bdn-EE-6KU">
23+ <rect key="frame" x="0.0" y="116" width="375" height="502"/>
24+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
25+ </tableView>
26+ </subviews>
27+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
28+ <constraints>
29+ <constraint firstItem="bdn-EE-6KU" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="Mwc-qc-ZfA"/>
30+ <constraint firstItem="bdn-EE-6KU" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="dww-F7-g9y"/>
31+ <constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="bdn-EE-6KU" secondAttribute="trailing" id="wlT-ZO-QGd"/>
32+ <constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="bdn-EE-6KU" secondAttribute="bottom" id="yXX-zW-vb8"/>
33+ </constraints>
34+ <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
35+ </view>
36+ <navigationItem key="navigationItem" largeTitleDisplayMode="always" id="caN-kg-RZ4"/>
37+ <connections>
38+ <outlet property="tableView" destination="bdn-EE-6KU" id="O4Z-at-Hzw"/>
39+ </connections>
40+ </viewController>
41+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
2542 </objects>
26− <point key="canvasLocation" x="1089" y="481"/>
43+ <point key="canvasLocation" x="2015.2" y="132.68365817091455"/>
2744 </scene>
2845 <!--Profile View Controller-->
2946 <scene sceneID="rQ6-TM-V7T">
@@ -34,7 +51,7 @@
3451 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
3552 <subviews>
3653 <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="cay-ea-rTl">
37− <rect key="frame" x="0.0" y="20" width="375" height="647"/>
54+ <rect key="frame" x="0.0" y="116" width="375" height="502"/>
3855 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
3956 <view key="tableHeaderView" contentMode="scaleToFill" id="kFZ-3c-OFY">
4057 <rect key="frame" x="0.0" y="0.0" width="375" height="199"/>
@@ -88,11 +105,8 @@
88105 <nil key="highlightedColor"/>
89106 </label>
90107 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yir-N6-Q6f">
91− <rect key="frame" x="246" y="0.0" width="97" height="30"/>
92− <state key="normal" title="New message"/>
93− <connections>
94− <action selector="sendMessage:" destination="R4D-Ao-uvG" eventType="touchUpInside" id="tQc-5f-SU3"/>
95− </connections>
108+ <rect key="frame" x="297" y="0.0" width="46" height="30"/>
109+ <state key="normal" title="Button"/>
96110 </button>
97111 </subviews>
98112 </stackView>
@@ -148,7 +162,7 @@
148162 </viewController>
149163 <placeholder placeholderIdentifier="IBFirstResponder" id="sap-zV-B7l" userLabel="First Responder" sceneMemberID="firstResponder"/>
150164 </objects>
151− <point key="canvasLocation" x="1884" y="1216"/>
165+ <point key="canvasLocation" x="2013.5999999999999" y="957.57121439280365"/>
152166 </scene>
153167 <!--Settings View Controller-->
154168 <scene sceneID="WVn-Qy-9tO">
@@ -185,7 +199,7 @@
185199 </tableViewController>
186200 <placeholder placeholderIdentifier="IBFirstResponder" id="xdg-ZK-4Jv" userLabel="First Responder" sceneMemberID="firstResponder"/>
187201 </objects>
188− <point key="canvasLocation" x="1980" y="1979"/>
202+ <point key="canvasLocation" x="1986" y="1756"/>
189203 </scene>
190204 <!--Invite View Controller-->
191205 <scene sceneID="DcO-6Y-Iko">
@@ -229,295 +243,7 @@
229243 </viewController>
230244 <placeholder placeholderIdentifier="IBFirstResponder" id="t8a-Sv-mbh" userLabel="First Responder" sceneMemberID="firstResponder"/>
231245 </objects>
232− <point key="canvasLocation" x="2799" y="1979"/>
233− </scene>
234− <!--Code View Controller-->
235− <scene sceneID="VW5-ny-vaB">
236− <objects>
237− <viewController storyboardIdentifier="CodeViewController" id="Lz1-1J-ywG" customClass="CodeViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
238− <view key="view" contentMode="scaleToFill" id="Rud-1x-pKL">
239− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
240− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
241− <subviews>
242− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Enter the code you received via mail" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hE6-cQ-NbO">
243− <rect key="frame" x="50" y="47" width="275.5" height="20.5"/>
244− <fontDescription key="fontDescription" type="system" pointSize="17"/>
245− <nil key="textColor"/>
246− <nil key="highlightedColor"/>
247− </label>
248− <stackView opaque="NO" contentMode="scaleToFill" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="2Gj-pC-RZ2">
249− <rect key="frame" x="37.5" y="99" width="300" height="58"/>
250− <subviews>
251− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="744-t1-YNn">
252− <rect key="frame" x="0.0" y="0.0" width="40" height="58"/>
253− <nil key="textColor"/>
254− <fontDescription key="fontDescription" type="system" pointSize="45"/>
255− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
256− </textField>
257− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="jcR-jp-s7a">
258− <rect key="frame" x="52" y="0.0" width="40" height="58"/>
259− <nil key="textColor"/>
260− <fontDescription key="fontDescription" type="system" pointSize="45"/>
261− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
262− </textField>
263− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="YKO-0M-KD8">
264− <rect key="frame" x="104" y="0.0" width="40" height="58"/>
265− <nil key="textColor"/>
266− <fontDescription key="fontDescription" type="system" pointSize="45"/>
267− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
268− </textField>
269− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="SmG-Ae-oOs">
270− <rect key="frame" x="156" y="0.0" width="40" height="58"/>
271− <nil key="textColor"/>
272− <fontDescription key="fontDescription" type="system" pointSize="45"/>
273− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
274− </textField>
275− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="vaP-rO-NZW">
276− <rect key="frame" x="208" y="0.0" width="40" height="58"/>
277− <nil key="textColor"/>
278− <fontDescription key="fontDescription" type="system" pointSize="45"/>
279− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
280− </textField>
281− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="qDh-32-HSn">
282− <rect key="frame" x="260" y="0.0" width="40" height="58"/>
283− <nil key="textColor"/>
284− <fontDescription key="fontDescription" type="system" pointSize="45"/>
285− <textInputTraits key="textInputTraits" keyboardType="numberPad"/>
286− </textField>
287− </subviews>
288− <constraints>
289− <constraint firstAttribute="height" constant="58" id="5tl-bI-7tm"/>
290− <constraint firstItem="YKO-0M-KD8" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="E7r-rk-4Mb"/>
291− <constraint firstItem="SmG-Ae-oOs" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Hkd-L6-qkf"/>
292− <constraint firstItem="qDh-32-HSn" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Koj-e5-Dof"/>
293− <constraint firstItem="vaP-rO-NZW" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Vzl-ZY-3yI"/>
294− <constraint firstItem="jcR-jp-s7a" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="bDe-cA-CGi"/>
295− <constraint firstAttribute="width" constant="300" id="gWy-t0-k14"/>
296− </constraints>
297− </stackView>
298− <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lCU-OF-giE">
299− <rect key="frame" x="0.0" y="617" width="375" height="50"/>
300− <subviews>
301− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AMw-Yp-yMs">
302− <rect key="frame" x="327" y="8" width="32" height="30"/>
303− <state key="normal" title="Next"/>
304− <connections>
305− <action selector="whereToGoNext:" destination="Lz1-1J-ywG" eventType="touchUpInside" id="1OA-n8-Gky"/>
306− </connections>
307− </button>
308− </subviews>
309− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
310− <constraints>
311− <constraint firstAttribute="bottom" secondItem="AMw-Yp-yMs" secondAttribute="bottom" constant="12" id="7qy-qR-6jm"/>
312− <constraint firstItem="AMw-Yp-yMs" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="lCU-OF-giE" secondAttribute="leading" constant="20" symbolic="YES" id="Bqz-qr-CNW"/>
313− <constraint firstAttribute="height" constant="50" id="Dyu-H3-S3f"/>
314− <constraint firstAttribute="trailing" secondItem="AMw-Yp-yMs" secondAttribute="trailing" constant="16" id="N19-bz-XCw"/>
315− <constraint firstItem="AMw-Yp-yMs" firstAttribute="top" secondItem="lCU-OF-giE" secondAttribute="top" constant="8" id="u6d-3F-1Y5"/>
316− </constraints>
317− </view>
318− </subviews>
319− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
320− <constraints>
321− <constraint firstItem="hE6-cQ-NbO" firstAttribute="top" secondItem="xwd-51-foC" secondAttribute="top" constant="27" id="8Gx-SH-Pc0"/>
322− <constraint firstItem="2Gj-pC-RZ2" firstAttribute="top" secondItem="hE6-cQ-NbO" secondAttribute="bottom" constant="31.5" id="DEY-u8-rFj"/>
323− <constraint firstItem="lCU-OF-giE" firstAttribute="leading" secondItem="xwd-51-foC" secondAttribute="leading" id="HFt-0X-LMb"/>
324− <constraint firstItem="lCU-OF-giE" firstAttribute="trailing" secondItem="xwd-51-foC" secondAttribute="trailing" id="Z71-jX-S5Q"/>
325− <constraint firstItem="2Gj-pC-RZ2" firstAttribute="centerX" secondItem="xwd-51-foC" secondAttribute="centerX" id="aSr-QZ-LuB"/>
326− <constraint firstItem="hE6-cQ-NbO" firstAttribute="centerX" secondItem="xwd-51-foC" secondAttribute="centerX" id="oFz-CS-SSk"/>
327− <constraint firstItem="lCU-OF-giE" firstAttribute="bottom" secondItem="xwd-51-foC" secondAttribute="bottom" id="vMF-KP-eIa"/>
328− </constraints>
329− <viewLayoutGuide key="safeArea" id="xwd-51-foC"/>
330− </view>
331− <connections>
332− <outlet property="bottomConstraint" destination="vMF-KP-eIa" id="a15-El-XZs"/>
333− <outlet property="f1" destination="744-t1-YNn" id="kaQ-nt-ubz"/>
334− <outlet property="f2" destination="jcR-jp-s7a" id="tjD-L6-nis"/>
335− <outlet property="f3" destination="YKO-0M-KD8" id="QHg-UM-Bta"/>
336− <outlet property="f4" destination="SmG-Ae-oOs" id="bwy-JB-My7"/>
337− <outlet property="f5" destination="vaP-rO-NZW" id="rNh-iH-648"/>
338− <outlet property="f6" destination="qDh-32-HSn" id="h4g-QY-abI"/>
339− </connections>
340− </viewController>
341− <placeholder placeholderIdentifier="IBFirstResponder" id="y6E-3d-hPA" userLabel="First Responder" sceneMemberID="firstResponder"/>
342− </objects>
343− <point key="canvasLocation" x="4381.6000000000004" y="1961.4692653673164"/>
344− </scene>
345− <!--Register Table View Controller-->
346− <scene sceneID="h6T-rh-iCS">
347− <objects>
348− <tableViewController storyboardIdentifier="RegisterTableViewController" id="gZg-8R-SiJ" customClass="RegisterTableViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
349− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="yDm-gG-Zw0">
350− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
351− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
352− <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
353− <prototypes>
354− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="cell111" textLabel="bby-bf-qyX" style="IBUITableViewCellStyleDefault" id="Ybe-Vg-GR0">
355− <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
356− <autoresizingMask key="autoresizingMask"/>
357− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Ybe-Vg-GR0" id="OZG-F0-QqJ">
358− <rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
359− <autoresizingMask key="autoresizingMask"/>
360− <subviews>
361− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Add faculty" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="bby-bf-qyX">
362− <rect key="frame" x="16" y="0.0" width="324" height="43.5"/>
363− <autoresizingMask key="autoresizingMask"/>
364− <fontDescription key="fontDescription" type="system" pointSize="17"/>
365− <nil key="textColor"/>
366− <nil key="highlightedColor"/>
367− </label>
368− </subviews>
369− </tableViewCellContentView>
370− </tableViewCell>
371− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="facultyCell" textLabel="8Xf-Sx-eEe" detailTextLabel="Vjg-Il-F07" style="IBUITableViewCellStyleSubtitle" id="xJW-zY-MeC">
372− <rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
373− <autoresizingMask key="autoresizingMask"/>
374− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xJW-zY-MeC" id="hnt-oe-CHh">
375− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
376− <autoresizingMask key="autoresizingMask"/>
377− <subviews>
378− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Add faculty" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8Xf-Sx-eEe">
379− <rect key="frame" x="16" y="5" width="87" height="20.5"/>
380− <autoresizingMask key="autoresizingMask"/>
381− <fontDescription key="fontDescription" type="system" pointSize="17"/>
382− <nil key="textColor"/>
383− <nil key="highlightedColor"/>
384− </label>
385− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Vjg-Il-F07">
386− <rect key="frame" x="16" y="25.5" width="44" height="14.5"/>
387− <autoresizingMask key="autoresizingMask"/>
388− <fontDescription key="fontDescription" type="system" pointSize="12"/>
389− <nil key="textColor"/>
390− <nil key="highlightedColor"/>
391− </label>
392− </subviews>
393− </tableViewCellContentView>
394− </tableViewCell>
395− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="nameCell" id="VPG-zq-xMh" customClass="InititalsViewCell" customModule="GDproject" customModuleProvider="target">
396− <rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
397− <autoresizingMask key="autoresizingMask"/>
398− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VPG-zq-xMh" id="jrO-rB-x0c">
399− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
400− <autoresizingMask key="autoresizingMask"/>
401− <subviews>
402− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hwQ-St-DAp">
403− <rect key="frame" x="16" y="7" width="343" height="30"/>
404− <constraints>
405− <constraint firstAttribute="height" constant="30" id="QXw-Sf-Hnk"/>
406− </constraints>
407− <nil key="textColor"/>
408− <fontDescription key="fontDescription" type="system" pointSize="17"/>
409− <textInputTraits key="textInputTraits"/>
410− </textField>
411− </subviews>
412− <constraints>
413− <constraint firstAttribute="bottom" secondItem="hwQ-St-DAp" secondAttribute="bottom" constant="6.5" id="3Kb-PR-ZPu"/>
414− <constraint firstItem="hwQ-St-DAp" firstAttribute="top" secondItem="jrO-rB-x0c" secondAttribute="top" constant="7" id="CyQ-kQ-mce"/>
415− <constraint firstAttribute="trailing" secondItem="hwQ-St-DAp" secondAttribute="trailing" constant="16" id="HKq-mF-8h9"/>
416− <constraint firstItem="hwQ-St-DAp" firstAttribute="leading" secondItem="jrO-rB-x0c" secondAttribute="leading" constant="16" id="NoW-FW-Q6L"/>
417− </constraints>
418− </tableViewCellContentView>
419− <connections>
420− <outlet property="initialsTextField" destination="hwQ-St-DAp" id="VU3-m6-FnI"/>
421− </connections>
422− </tableViewCell>
423− </prototypes>
424− <connections>
425− <outlet property="dataSource" destination="gZg-8R-SiJ" id="OVm-5H-nyP"/>
426− <outlet property="delegate" destination="gZg-8R-SiJ" id="khe-nG-0w4"/>
427− </connections>
428− </tableView>
429− </tableViewController>
430− <placeholder placeholderIdentifier="IBFirstResponder" id="0cS-ao-ZWH" userLabel="First Responder" sceneMemberID="firstResponder"/>
431− </objects>
432− <point key="canvasLocation" x="5925.6000000000004" y="2041.529235382309"/>
433− </scene>
434− <!--Faculty Table View Controller-->
435− <scene sceneID="WcK-wN-L0e">
436− <objects>
437− <tableViewController storyboardIdentifier="FacultyTableViewController" id="wiz-jF-9HF" customClass="FacultyTableViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
438− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="Iny-a7-zjv">
439− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
440− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
441− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
442− <prototypes>
443− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="F" textLabel="mSQ-7c-C8A" detailTextLabel="YuF-0p-znr" style="IBUITableViewCellStyleSubtitle" id="Otu-BR-9o9">
444− <rect key="frame" x="0.0" y="28" width="375" height="44"/>
445− <autoresizingMask key="autoresizingMask"/>
446− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Otu-BR-9o9" id="2Vm-f8-txH">
447− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
448− <autoresizingMask key="autoresizingMask"/>
449− <subviews>
450− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="mSQ-7c-C8A">
451− <rect key="frame" x="16" y="5" width="33.5" height="20.5"/>
452− <autoresizingMask key="autoresizingMask"/>
453− <fontDescription key="fontDescription" type="system" pointSize="17"/>
454− <nil key="textColor"/>
455− <nil key="highlightedColor"/>
456− </label>
457− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="YuF-0p-znr">
458− <rect key="frame" x="16" y="25.5" width="44" height="14.5"/>
459− <autoresizingMask key="autoresizingMask"/>
460− <fontDescription key="fontDescription" type="system" pointSize="12"/>
461− <nil key="textColor"/>
462− <nil key="highlightedColor"/>
463− </label>
464− </subviews>
465− </tableViewCellContentView>
466− </tableViewCell>
467− </prototypes>
468− <connections>
469− <outlet property="dataSource" destination="wiz-jF-9HF" id="db0-qR-UJy"/>
470− <outlet property="delegate" destination="wiz-jF-9HF" id="i3e-Uc-EfR"/>
471− </connections>
472− </tableView>
473− </tableViewController>
474− <placeholder placeholderIdentifier="IBFirstResponder" id="Kkr-Cr-ZiV" userLabel="First Responder" sceneMemberID="firstResponder"/>
475− </objects>
476− <point key="canvasLocation" x="6804" y="2044"/>
477− </scene>
478− <!--Simplified Channels List-->
479− <scene sceneID="gAa-jy-vpG">
480− <objects>
481− <tableViewController storyboardIdentifier="SimplifiedChannelsList" id="pgD-Fz-bkD" customClass="SimplifiedChannelsList" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
482− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="Onz-Ne-JgO">
483− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
484− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
485− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
486− <prototypes>
487− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" restorationIdentifier="cell" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell1" textLabel="mZB-IA-VFq" detailTextLabel="6A8-yj-Eqe" style="IBUITableViewCellStyleSubtitle" id="6dT-km-gZC">
488− <rect key="frame" x="0.0" y="28" width="375" height="44"/>
489− <autoresizingMask key="autoresizingMask"/>
490− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="6dT-km-gZC" id="h7U-va-4PX">
491− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
492− <autoresizingMask key="autoresizingMask"/>
493− <subviews>
494− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="mZB-IA-VFq">
495− <rect key="frame" x="16" y="5" width="33.5" height="20.5"/>
496− <autoresizingMask key="autoresizingMask"/>
497− <fontDescription key="fontDescription" type="system" pointSize="17"/>
498− <nil key="textColor"/>
499− <nil key="highlightedColor"/>
500− </label>
501− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6A8-yj-Eqe">
502− <rect key="frame" x="16" y="25.5" width="44" height="14.5"/>
503− <autoresizingMask key="autoresizingMask"/>
504− <fontDescription key="fontDescription" type="system" pointSize="12"/>
505− <nil key="textColor"/>
506− <nil key="highlightedColor"/>
507− </label>
508− </subviews>
509− </tableViewCellContentView>
510− </tableViewCell>
511− </prototypes>
512− <connections>
513− <outlet property="dataSource" destination="pgD-Fz-bkD" id="V4y-ql-GOS"/>
514− <outlet property="delegate" destination="pgD-Fz-bkD" id="Avz-4G-8j6"/>
515− </connections>
516− </tableView>
517− </tableViewController>
518− <placeholder placeholderIdentifier="IBFirstResponder" id="731-nV-bC3" userLabel="First Responder" sceneMemberID="firstResponder"/>
519− </objects>
520− <point key="canvasLocation" x="4372" y="-598"/>
246+ <point key="canvasLocation" x="2803" y="1756"/>
521247 </scene>
522248 <!--Channel List Controller-->
523249 <scene sceneID="4eb-Jz-gcx">
@@ -615,7 +341,7 @@
615341 </viewController>
616342 <placeholder placeholderIdentifier="IBFirstResponder" id="fzv-8a-15V" userLabel="First Responder" sceneMemberID="firstResponder"/>
617343 </objects>
618− <point key="canvasLocation" x="3577" y="-598"/>
344+ <point key="canvasLocation" x="3560.8000000000002" y="-597.75112443778119"/>
619345 </scene>
620346 <!--New Post View Controller-->
621347 <scene sceneID="TVK-xu-UdJ">
@@ -625,36 +351,23 @@
625351 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
626352 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
627353 <subviews>
628− <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aRT-Du-PVE">
629− <rect key="frame" x="0.0" y="62" width="375" height="605"/>
354+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sSz-uJ-A7n">
355+ <rect key="frame" x="0.0" y="20" width="375" height="647"/>
630356 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
631357 </view>
632− <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bHv-9b-9uA">
633− <rect key="frame" x="16" y="32" width="343" height="30"/>
634− <constraints>
635− <constraint firstAttribute="height" constant="30" id="QPs-3f-AfA"/>
636− </constraints>
637− <state key="normal" title="Edit hashtags"/>
638− <connections>
639− <action selector="chooseTags:" destination="uED-wX-77j" eventType="touchUpInside" id="jvf-w2-K2f"/>
640− </connections>
641− </button>
642358 </subviews>
643359 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
644360 <constraints>
645− <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="aRT-Du-PVE" secondAttribute="trailing" id="2ee-e8-G7A"/>
646− <constraint firstItem="aRT-Du-PVE" firstAttribute="top" secondItem="bHv-9b-9uA" secondAttribute="bottom" id="6As-MU-bEh"/>
647− <constraint firstItem="bHv-9b-9uA" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" constant="16" id="OIV-hF-TBs"/>
648− <constraint firstItem="bHv-9b-9uA" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" constant="12" id="REt-Jv-IfH"/>
649− <constraint firstItem="aRT-Du-PVE" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="UBy-Ch-zSL"/>
650− <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="bHv-9b-9uA" secondAttribute="trailing" constant="16" id="Ufp-mQ-Xeo"/>
651− <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="aRT-Du-PVE" secondAttribute="bottom" id="x3f-eb-ACt"/>
361+ <constraint firstItem="sSz-uJ-A7n" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="2J7-Bi-PzG"/>
362+ <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="sSz-uJ-A7n" secondAttribute="trailing" id="HrU-bs-qsE"/>
363+ <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="sSz-uJ-A7n" secondAttribute="bottom" id="oZ7-xQ-9Cb"/>
364+ <constraint firstItem="sSz-uJ-A7n" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" id="zuN-mZ-hgU"/>
652365 </constraints>
653366 <viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
654367 </view>
655368 <connections>
656− <outlet property="bottomTextViewConstraint" destination="x3f-eb-ACt" id="ktT-im-InH"/>
657− <outlet property="view1" destination="aRT-Du-PVE" id="DXD-HR-NcE"/>
369+ <outlet property="bottomTextViewConstraint" destination="oZ7-xQ-9Cb" id="6In-71-0TX"/>
370+ <outlet property="view1" destination="sSz-uJ-A7n" id="5nX-oT-kUi"/>
658371 </connections>
659372 </viewController>
660373 <placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -679,389 +392,91 @@
679392 </objects>
680393 <point key="canvasLocation" x="3444" y="129.98500749625188"/>
681394 </scene>
682− <!--Taggs Selection View Controller-->
683− <scene sceneID="74G-Lc-cqT">
395+ <!--Log In View Controller-->
396+ <scene sceneID="Pkd-pB-bQs">
684397 <objects>
685− <viewController storyboardIdentifier="TaggsSelectionViewController" id="rQl-ri-9O8" customClass="TaggsSelectionViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
686− <view key="view" contentMode="scaleToFill" id="k3T-8B-NVf">
398+ <viewController storyboardIdentifier="LogInController" id="ZCz-70-hDh" customClass="LogInViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
399+ <view key="view" contentMode="scaleToFill" id="1q2-4g-KZs">
687400 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
688401 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
689402 <subviews>
690− <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yeR-J3-ysT">
691− <rect key="frame" x="16" y="131" width="343" height="142"/>
692− <constraints>
693− <constraint firstAttribute="height" constant="142" id="1By-sC-rMT"/>
694− </constraints>
695− </containerView>
696− <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lEu-rZ-H6U">
697− <rect key="frame" x="16" y="306" width="343" height="184"/>
698− <constraints>
699− <constraint firstAttribute="height" constant="184" id="F0W-3R-hCj"/>
700− </constraints>
701− </containerView>
702− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Add tags:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uXC-Rm-Hek">
703− <rect key="frame" x="16" y="28" width="73" height="21"/>
704− <constraints>
705− <constraint firstAttribute="height" constant="21" id="KZW-ld-K8d"/>
706− </constraints>
707− <fontDescription key="fontDescription" type="system" pointSize="17"/>
708− <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
709− <nil key="highlightedColor"/>
710− </label>
711− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Suggested tags:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hvS-Ix-A23">
712− <rect key="frame" x="16" y="106" width="126" height="21"/>
713− <constraints>
714− <constraint firstAttribute="height" constant="21" id="ZJb-Aw-bLx"/>
715− </constraints>
716− <fontDescription key="fontDescription" type="system" pointSize="17"/>
717− <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
718− <nil key="highlightedColor"/>
719− </label>
720− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Chosen tags:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lxp-KC-Iua">
721− <rect key="frame" x="16" y="281" width="101" height="21"/>
722− <constraints>
723− <constraint firstAttribute="height" constant="21" id="aT7-BK-i42"/>
724− </constraints>
725− <fontDescription key="fontDescription" type="system" pointSize="17"/>
726− <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
727− <nil key="highlightedColor"/>
728− </label>
729− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="BgX-NT-7NG" customClass="TKTextField" customModule="TaggerKit">
730− <rect key="frame" x="16" y="57" width="343" height="30"/>
731− <constraints>
732− <constraint firstAttribute="height" constant="30" id="dBr-rd-Cg8"/>
733− </constraints>
734− <nil key="textColor"/>
735− <fontDescription key="fontDescription" type="system" pointSize="14"/>
736− <textInputTraits key="textInputTraits"/>
737− </textField>
403+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="UwC-m5-jA5">
404+ <rect key="frame" x="16" y="100" width="343" height="83"/>
405+ <subviews>
406+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Log In" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="efn-ze-jca">
407+ <rect key="frame" x="0.0" y="0.0" width="343" height="41"/>
408+ <fontDescription key="fontDescription" type="boldSystem" pointSize="34"/>
409+ <nil key="textColor"/>
410+ <nil key="highlightedColor"/>
411+ </label>
412+ <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Mail" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="mFP-WG-jY5">
413+ <rect key="frame" x="0.0" y="53" width="343" height="30"/>
414+ <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
415+ <nil key="textColor"/>
416+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
417+ <textInputTraits key="textInputTraits"/>
418+ </textField>
419+ </subviews>
420+ </stackView>
738421 </subviews>
739422 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
740423 <constraints>
741− <constraint firstItem="hvS-Ix-A23" firstAttribute="top" secondItem="BgX-NT-7NG" secondAttribute="bottom" constant="19" id="17U-ae-Gxa"/>
742− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="yeR-J3-ysT" secondAttribute="trailing" constant="16" id="9gG-QD-LG4"/>
743− <constraint firstItem="lxp-KC-Iua" firstAttribute="top" secondItem="yeR-J3-ysT" secondAttribute="bottom" constant="8" id="C3R-dM-Fzj"/>
744− <constraint firstItem="uXC-Rm-Hek" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="E6w-kw-7Uo"/>
745− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="hvS-Ix-A23" secondAttribute="trailing" constant="233" id="GLM-Fj-UeZ"/>
746− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lxp-KC-Iua" secondAttribute="trailing" constant="258" id="Pbc-Ul-Bqf"/>
747− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="uXC-Rm-Hek" secondAttribute="trailing" constant="286" id="Uc1-pS-uKg"/>
748− <constraint firstItem="lEu-rZ-H6U" firstAttribute="top" secondItem="lxp-KC-Iua" secondAttribute="bottom" constant="4" id="aew-vr-F7L"/>
749− <constraint firstItem="uXC-Rm-Hek" firstAttribute="top" secondItem="Oc2-oW-bST" secondAttribute="top" constant="8" id="dGW-ps-wNH"/>
750− <constraint firstItem="lxp-KC-Iua" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="gmr-z4-RMQ"/>
751− <constraint firstItem="BgX-NT-7NG" firstAttribute="top" secondItem="uXC-Rm-Hek" secondAttribute="bottom" constant="8" id="jqp-Lv-waU"/>
752− <constraint firstItem="yeR-J3-ysT" firstAttribute="top" secondItem="hvS-Ix-A23" secondAttribute="bottom" constant="4" id="nZ3-oH-0AF"/>
753− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="BgX-NT-7NG" secondAttribute="trailing" constant="16" id="pPk-Ih-GDO"/>
754− <constraint firstItem="yeR-J3-ysT" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qBn-xg-Ioc"/>
755− <constraint firstItem="lEu-rZ-H6U" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qCJ-rc-qBq"/>
756− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lEu-rZ-H6U" secondAttribute="trailing" constant="16" id="vaR-Zr-5nI"/>
757− <constraint firstItem="hvS-Ix-A23" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="vcb-xj-bM8"/>
758− <constraint firstItem="BgX-NT-7NG" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="xOL-J4-JIV"/>
424+ <constraint firstItem="UwC-m5-jA5" firstAttribute="leading" secondItem="LOR-Yw-0FU" secondAttribute="leading" constant="16" id="M6z-nU-H40"/>
425+ <constraint firstItem="LOR-Yw-0FU" firstAttribute="trailing" secondItem="UwC-m5-jA5" secondAttribute="trailing" constant="16" id="jST-rr-MMX"/>
426+ <constraint firstItem="UwC-m5-jA5" firstAttribute="top" secondItem="LOR-Yw-0FU" secondAttribute="top" constant="80" id="rvy-Ii-bwS"/>
759427 </constraints>
760− <viewLayoutGuide key="safeArea" id="Oc2-oW-bST"/>
428+ <viewLayoutGuide key="safeArea" id="LOR-Yw-0FU"/>
761429 </view>
762430 <connections>
763− <outlet property="addTagsTextField" destination="BgX-NT-7NG" id="3vt-U9-NYI"/>
764− <outlet property="searchContainerView" destination="yeR-J3-ysT" id="SzT-fM-A6H"/>
765− <outlet property="testContainer" destination="lEu-rZ-H6U" id="DTe-9O-VAi"/>
431+ <outlet property="mailTextField" destination="mFP-WG-jY5" id="7SN-qe-DDm"/>
766432 </connections>
767433 </viewController>
768− <placeholder placeholderIdentifier="IBFirstResponder" id="eoH-1e-A6A" userLabel="First Responder" sceneMemberID="firstResponder"/>
769− </objects>
770− <point key="canvasLocation" x="4293.6000000000004" y="132.68365817091455"/>
771− </scene>
772− <!--Messages View Controller-->
773− <scene sceneID="WSW-fr-Vf8">
774− <objects>
775− <tableViewController storyboardIdentifier="MessagesViewController" id="KLf-CK-diQ" customClass="MessagesViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
776− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="13B-QX-K78">
777− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
778− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
779− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
780− <prototypes>
781− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MessageViewCell" rowHeight="78" id="67C-fT-WEV" customClass="MessageViewCell" customModule="GDproject" customModuleProvider="target">
782− <rect key="frame" x="0.0" y="28" width="375" height="78"/>
783− <autoresizingMask key="autoresizingMask"/>
784− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="67C-fT-WEV" id="O3b-Xv-UNk">
785− <rect key="frame" x="0.0" y="0.0" width="375" height="77.5"/>
786− <autoresizingMask key="autoresizingMask"/>
787− <subviews>
788− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xAY-IF-RpX">
789− <rect key="frame" x="229" y="11" width="130" height="15"/>
790− <constraints>
791− <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="130" id="f99-ZF-f8h"/>
792− </constraints>
793− <fontDescription key="fontDescription" type="system" pointSize="12"/>
794− <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
795− <nil key="highlightedColor"/>
796− </label>
797− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FG3-gU-0r1">
798− <rect key="frame" x="16" y="11" width="46" height="22"/>
799− <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
800− <nil key="textColor"/>
801− <nil key="highlightedColor"/>
802− </label>
803− <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nTy-rK-XTr">
804− <rect key="frame" x="16" y="49" width="343" height="18"/>
805− <fontDescription key="fontDescription" type="system" pointSize="15"/>
806− <nil key="textColor"/>
807− <nil key="highlightedColor"/>
808− </label>
809− </subviews>
810− <constraints>
811− <constraint firstItem="nTy-rK-XTr" firstAttribute="top" secondItem="xAY-IF-RpX" secondAttribute="bottom" constant="23" id="09Y-aK-nD9"/>
812− <constraint firstItem="FG3-gU-0r1" firstAttribute="top" secondItem="O3b-Xv-UNk" secondAttribute="topMargin" id="4Hp-d5-9An"/>
813− <constraint firstItem="xAY-IF-RpX" firstAttribute="top" secondItem="O3b-Xv-UNk" secondAttribute="topMargin" id="G4f-oJ-7ud"/>
814− <constraint firstItem="nTy-rK-XTr" firstAttribute="trailing" secondItem="O3b-Xv-UNk" secondAttribute="trailingMargin" id="MaE-VM-KhL"/>
815− <constraint firstItem="nTy-rK-XTr" firstAttribute="leading" secondItem="O3b-Xv-UNk" secondAttribute="leadingMargin" id="OIX-rY-Leo"/>
816− <constraint firstItem="nTy-rK-XTr" firstAttribute="top" secondItem="FG3-gU-0r1" secondAttribute="bottom" constant="16" id="Qdj-s3-t60"/>
817− <constraint firstItem="nTy-rK-XTr" firstAttribute="bottom" secondItem="O3b-Xv-UNk" secondAttribute="bottomMargin" id="Rv3-Mz-Aed"/>
818− <constraint firstItem="FG3-gU-0r1" firstAttribute="leading" secondItem="O3b-Xv-UNk" secondAttribute="leadingMargin" id="iN1-KG-dYn"/>
819− <constraint firstItem="xAY-IF-RpX" firstAttribute="trailing" secondItem="O3b-Xv-UNk" secondAttribute="trailingMargin" id="opV-4x-VCk"/>
820− <constraint firstItem="xAY-IF-RpX" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FG3-gU-0r1" secondAttribute="trailing" constant="4" id="x9r-sM-t4x"/>
821− </constraints>
822− </tableViewCellContentView>
823− <connections>
824− <outlet property="dateLabel" destination="xAY-IF-RpX" id="fcz-re-BXk"/>
825− <outlet property="dialogName" destination="FG3-gU-0r1" id="gd7-ND-wCi"/>
826− <outlet property="lastMessagePreview" destination="nTy-rK-XTr" id="Cmo-IJ-2r0"/>
827− </connections>
828− </tableViewCell>
829− </prototypes>
830− <connections>
831− <outlet property="dataSource" destination="KLf-CK-diQ" id="LjF-Uw-Xhq"/>
832− <outlet property="delegate" destination="KLf-CK-diQ" id="yJZ-wH-O3v"/>
833− </connections>
834− </tableView>
835− </tableViewController>
836− <placeholder placeholderIdentifier="IBFirstResponder" id="fu3-z4-EY7" userLabel="First Responder" sceneMemberID="firstResponder"/>
837− </objects>
838− <point key="canvasLocation" x="2681" y="918"/>
839− </scene>
840− <!--People To Write View Controller-->
841− <scene sceneID="6Td-bq-Ebf">
842− <objects>
843− <tableViewController storyboardIdentifier="PeopleToWriteViewController" id="rUc-Tv-hWE" customClass="PeopleToWriteViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
844− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsSelectionDuringEditing="YES" allowsMultipleSelection="YES" allowsMultipleSelectionDuringEditing="YES" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="PDb-NB-Ey6">
845− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
846− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
847− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
848− <prototypes>
849− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="peopleToWriteCell" textLabel="e4H-yo-W57" style="IBUITableViewCellStyleDefault" id="5ue-Sf-Blf">
850− <rect key="frame" x="0.0" y="28" width="375" height="44"/>
851− <autoresizingMask key="autoresizingMask"/>
852− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5ue-Sf-Blf" id="8Dr-YE-x7M">
853− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
854− <autoresizingMask key="autoresizingMask"/>
855− <subviews>
856− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="e4H-yo-W57">
857− <rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
858− <autoresizingMask key="autoresizingMask"/>
859− <fontDescription key="fontDescription" type="system" pointSize="17"/>
860− <nil key="textColor"/>
861− <nil key="highlightedColor"/>
862− </label>
863− </subviews>
864− </tableViewCellContentView>
865− </tableViewCell>
866− </prototypes>
867− <connections>
868− <outlet property="dataSource" destination="rUc-Tv-hWE" id="cuc-oZ-Sna"/>
869− <outlet property="delegate" destination="rUc-Tv-hWE" id="hw6-6X-Rlx"/>
870− </connections>
871− </tableView>
872− </tableViewController>
873− <placeholder placeholderIdentifier="IBFirstResponder" id="Zp5-b5-nn2" userLabel="First Responder" sceneMemberID="firstResponder"/>
434+ <placeholder placeholderIdentifier="IBFirstResponder" id="6e8-oo-bbc" userLabel="First Responder" sceneMemberID="firstResponder"/>
874435 </objects>
875− <point key="canvasLocation" x="3614" y="938"/>
876− </scene>
877− <!--Chat Info View Controller-->
878− <scene sceneID="1br-Xg-fR9">
879− <objects>
880− <tableViewController storyboardIdentifier="ChatInfoViewController" id="Rfd-Hp-Qqv" customClass="ChatInfoViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
881− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="Rvg-ok-cnE">
882− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
883− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
884− <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
885− <prototypes>
886− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" textLabel="EdJ-of-2FG" style="IBUITableViewCellStyleDefault" id="hl5-Uc-R53">
887− <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
888− <autoresizingMask key="autoresizingMask"/>
889− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hl5-Uc-R53" id="Oy5-4e-dPI">
890− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
891− <autoresizingMask key="autoresizingMask"/>
892− <subviews>
893− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="EdJ-of-2FG">
894− <rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
895− <autoresizingMask key="autoresizingMask"/>
896− <fontDescription key="fontDescription" type="system" pointSize="17"/>
897− <nil key="textColor"/>
898− <nil key="highlightedColor"/>
899− </label>
900− </subviews>
901− </tableViewCellContentView>
902− </tableViewCell>
903− </prototypes>
904− <sections/>
905− <connections>
906− <outlet property="dataSource" destination="Rfd-Hp-Qqv" id="ThC-G8-che"/>
907− <outlet property="delegate" destination="Rfd-Hp-Qqv" id="1WG-zg-Ahf"/>
908− </connections>
909− </tableView>
910− </tableViewController>
911− <placeholder placeholderIdentifier="IBFirstResponder" id="KPW-41-EQd" userLabel="First Responder" sceneMemberID="firstResponder"/>
912− </objects>
913− <point key="canvasLocation" x="5057" y="938"/>
914− </scene>
915− <!--Tags Suggestion Controller-->
916− <scene sceneID="gfS-IA-vBj">
917− <objects>
918− <tableViewController storyboardIdentifier="TagsSuggestionController" id="shX-JH-apo" customClass="TagsSuggestionController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
919− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="jTj-mU-lli">
920− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
921− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
922− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
923− <prototypes>
924− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="cell" textLabel="Lbu-Z7-fTN" style="IBUITableViewCellStyleDefault" id="pnl-jg-9DL">
925− <rect key="frame" x="0.0" y="28" width="375" height="44"/>
926− <autoresizingMask key="autoresizingMask"/>
927− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pnl-jg-9DL" id="Vsm-Ic-k7e">
928− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
929− <autoresizingMask key="autoresizingMask"/>
930− <subviews>
931− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Lbu-Z7-fTN">
932− <rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
933− <autoresizingMask key="autoresizingMask"/>
934− <fontDescription key="fontDescription" type="system" pointSize="17"/>
935− <nil key="textColor"/>
936− <nil key="highlightedColor"/>
937− </label>
938− </subviews>
939− </tableViewCellContentView>
940− </tableViewCell>
941− </prototypes>
942− <connections>
943− <outlet property="dataSource" destination="shX-JH-apo" id="a9b-xm-VIg"/>
944− <outlet property="delegate" destination="shX-JH-apo" id="Cg4-aC-E7h"/>
945− </connections>
946− </tableView>
947− </tableViewController>
948− <placeholder placeholderIdentifier="IBFirstResponder" id="RsJ-xx-GJW" userLabel="First Responder" sceneMemberID="firstResponder"/>
949− </objects>
950− <point key="canvasLocation" x="5925" y="1339"/>
951− </scene>
952− <!--Channel View Controller-->
953− <scene sceneID="myW-UY-uGB">
954− <objects>
955− <tableViewController storyboardIdentifier="ChannelViewController" id="M45-Em-JMM" customClass="ChannelViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
956− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="poy-7L-m8s">
957− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
958− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
959− <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
960− <prototypes>
961− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="titleCell" id="x0n-Is-bsF" customClass="TitleCell" customModule="GDproject" customModuleProvider="target">
962− <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
963− <autoresizingMask key="autoresizingMask"/>
964− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="x0n-Is-bsF" id="5aI-NN-BRQ">
965− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
966− <autoresizingMask key="autoresizingMask"/>
967− <subviews>
968− <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name the channel" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="jTk-cs-cpn">
969− <rect key="frame" x="16" y="7" width="343" height="30"/>
970− <constraints>
971− <constraint firstAttribute="height" constant="30" id="ZDL-Wx-W4e"/>
972− </constraints>
973− <nil key="textColor"/>
974− <fontDescription key="fontDescription" type="system" pointSize="17"/>
975− <textInputTraits key="textInputTraits"/>
976− </textField>
977− </subviews>
978− <constraints>
979− <constraint firstAttribute="trailing" secondItem="jTk-cs-cpn" secondAttribute="trailing" constant="16" id="KLT-Mg-Igg"/>
980− <constraint firstAttribute="bottom" secondItem="jTk-cs-cpn" secondAttribute="bottom" constant="6.5" id="Yuh-81-wLm"/>
981− <constraint firstItem="jTk-cs-cpn" firstAttribute="leading" secondItem="5aI-NN-BRQ" secondAttribute="leading" constant="16" id="tx2-BD-LW1"/>
982− <constraint firstItem="jTk-cs-cpn" firstAttribute="top" secondItem="5aI-NN-BRQ" secondAttribute="top" constant="7" id="ufD-Sr-H0c"/>
983− </constraints>
984− </tableViewCellContentView>
985− <connections>
986− <outlet property="titleLabel" destination="jTk-cs-cpn" id="ysU-SK-thv"/>
987− </connections>
988− </tableViewCell>
989− </prototypes>
990− <sections/>
991− <connections>
992− <outlet property="dataSource" destination="M45-Em-JMM" id="zIt-LL-u3B"/>
993− <outlet property="delegate" destination="M45-Em-JMM" id="8oD-9d-gx0"/>
994− </connections>
995− </tableView>
996− </tableViewController>
997− <placeholder placeholderIdentifier="IBFirstResponder" id="W3K-lW-jpq" userLabel="First Responder" sceneMemberID="firstResponder"/>
998− </objects>
999− <point key="canvasLocation" x="5844" y="448"/>
1000− </scene>
1001− <!--Add To ChannelVC-->
1002− <scene sceneID="Qir-mq-wma">
1003− <objects>
1004− <tableViewController storyboardIdentifier="AddToChannelVC" id="sZD-zJ-IzQ" customClass="AddToChannelVC" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
1005− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="yj4-wM-mw1">
1006− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
1007− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
1008− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
1009− <prototypes>
1010− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="xMi-Gz-AGg">
1011− <rect key="frame" x="0.0" y="28" width="375" height="44"/>
1012− <autoresizingMask key="autoresizingMask"/>
1013− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xMi-Gz-AGg" id="Lj0-2E-Ai9">
1014− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
1015− <autoresizingMask key="autoresizingMask"/>
1016− </tableViewCellContentView>
1017− </tableViewCell>
1018− </prototypes>
1019− <connections>
1020− <outlet property="dataSource" destination="sZD-zJ-IzQ" id="RJA-hG-8Bd"/>
1021− <outlet property="delegate" destination="sZD-zJ-IzQ" id="zlr-yK-CDk"/>
1022− </connections>
1023− </tableView>
1024− </tableViewController>
1025− <placeholder placeholderIdentifier="IBFirstResponder" id="kT3-kK-tSX" userLabel="First Responder" sceneMemberID="firstResponder"/>
1026− </objects>
1027− <point key="canvasLocation" x="6548" y="448"/>
436+ <point key="canvasLocation" x="-466" y="-821"/>
1028437 </scene>
1029438 <!--Posts-->
1030439 <scene sceneID="RSd-UJ-34B">
1031440 <objects>
1032− <navigationController storyboardIdentifier="navChannels" automaticallyAdjustsScrollViewInsets="NO" id="NuV-ZG-ld2" sceneMemberID="viewController">
1033− <tabBarItem key="tabBarItem" title="Posts" image="5" selectedImage="5" id="dH2-sL-YsR"/>
441+ <navigationController automaticallyAdjustsScrollViewInsets="NO" id="NuV-ZG-ld2" sceneMemberID="viewController">
442+ <tabBarItem key="tabBarItem" title="Posts" id="dH2-sL-YsR"/>
1034443 <toolbarItems/>
1035444 <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="6qB-3A-tuL">
1036445 <rect key="frame" x="0.0" y="20" width="375" height="96"/>
1037446 <autoresizingMask key="autoresizingMask"/>
1038447 </navigationBar>
1039448 <nil name="viewControllers"/>
449+ <connections>
450+ <segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="ehh-1b-ZGK"/>
451+ </connections>
1040452 </navigationController>
1041453 <placeholder placeholderIdentifier="IBFirstResponder" id="POV-5T-jeQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
1042454 </objects>
1043− <point key="canvasLocation" x="1089" y="-306"/>
455+ <point key="canvasLocation" x="1088.8" y="132.68365817091455"/>
1044456 </scene>
1045457 <!--Profile-->
1046458 <scene sceneID="dJj-Hp-Wa9">
1047459 <objects>
1048− <navigationController storyboardIdentifier="navPosts" automaticallyAdjustsScrollViewInsets="NO" id="tae-5q-wvT" sceneMemberID="viewController">
1049− <tabBarItem key="tabBarItem" title="Profile" image="1" selectedImage="1" id="lYy-LQ-AcR"/>
460+ <navigationController automaticallyAdjustsScrollViewInsets="NO" id="tae-5q-wvT" sceneMemberID="viewController">
461+ <tabBarItem key="tabBarItem" title="Profile" id="lYy-LQ-AcR"/>
1050462 <toolbarItems/>
1051463 <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="q3a-ph-c8V">
1052464 <rect key="frame" x="0.0" y="20" width="375" height="96"/>
1053465 <autoresizingMask key="autoresizingMask"/>
1054466 </navigationBar>
1055467 <nil name="viewControllers"/>
468+ <connections>
469+ <segue destination="R4D-Ao-uvG" kind="relationship" relationship="rootViewController" id="aF6-zK-hCB"/>
470+ </connections>
1056471 </navigationController>
1057472 <placeholder placeholderIdentifier="IBFirstResponder" id="Fvm-qf-2Ve" userLabel="First Responder" sceneMemberID="firstResponder"/>
1058473 </objects>
1059− <point key="canvasLocation" x="1015" y="1216"/>
474+ <point key="canvasLocation" x="1089" y="958"/>
1060475 </scene>
1061− <!--Tabbar Controller-->
476+ <!--Tab Bar Controller-->
1062477 <scene sceneID="HCR-WO-p7g">
1063478 <objects>
1064− <tabBarController storyboardIdentifier="TabbarController" automaticallyAdjustsScrollViewInsets="NO" id="IeP-4W-8LT" customClass="TabbarController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
479+ <tabBarController storyboardIdentifier="TabBar" automaticallyAdjustsScrollViewInsets="NO" id="IeP-4W-8LT" sceneMemberID="viewController">
1065480 <toolbarItems/>
1066481 <tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="3pl-mU-U30">
1067482 <rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
@@ -1070,7 +485,6 @@
1070485 </tabBar>
1071486 <connections>
1072487 <segue destination="NuV-ZG-ld2" kind="relationship" relationship="viewControllers" id="XuX-8s-fZU"/>
1073− <segue destination="gt4-mD-66Q" kind="relationship" relationship="viewControllers" id="QM3-FF-LMu"/>
1074488 <segue destination="tae-5q-wvT" kind="relationship" relationship="viewControllers" id="wCJ-4N-lfC"/>
1075489 </connections>
1076490 </tabBarController>
@@ -1078,40 +492,5 @@
1078492 </objects>
1079493 <point key="canvasLocation" x="-466" y="641"/>
1080494 </scene>
1081− <!--News Controller-->
1082− <scene sceneID="kf1-SJ-kcp">
1083− <objects>
1084− <viewController storyboardIdentifier="NewsController" id="R7p-5c-Vzl" customClass="NewsController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
1085− <view key="view" contentMode="scaleToFill" id="Kx5-cu-FC2">
1086− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
1087− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
1088− <subviews>
1089− <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="5IP-vK-phq">
1090− <rect key="frame" x="0.0" y="20" width="375" height="647"/>
1091− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
1092− </tableView>
1093− </subviews>
1094− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
1095− <constraints>
1096− <constraint firstItem="5IP-vK-phq" firstAttribute="top" secondItem="qGo-Sq-Oz2" secondAttribute="top" id="HvO-w8-yYd"/>
1097− <constraint firstItem="5IP-vK-phq" firstAttribute="leading" secondItem="qGo-Sq-Oz2" secondAttribute="leading" id="NTk-fa-llk"/>
1098− <constraint firstItem="qGo-Sq-Oz2" firstAttribute="bottom" secondItem="5IP-vK-phq" secondAttribute="bottom" id="mAj-tJ-R30"/>
1099− <constraint firstItem="qGo-Sq-Oz2" firstAttribute="trailing" secondItem="5IP-vK-phq" secondAttribute="trailing" id="pcE-yb-fxC"/>
1100− </constraints>
1101− <viewLayoutGuide key="safeArea" id="qGo-Sq-Oz2"/>
1102− </view>
1103− <connections>
1104− <outlet property="tableView" destination="5IP-vK-phq" id="EQe-eC-W7P"/>
1105− </connections>
1106− </viewController>
1107− <placeholder placeholderIdentifier="IBFirstResponder" id="6Lk-UL-mQL" userLabel="First Responder" sceneMemberID="firstResponder"/>
1108− </objects>
1109− <point key="canvasLocation" x="5426" y="-235"/>
1110− </scene>
1111495 </scenes>
1112− <resources>
1113− <image name="1" width="30" height="30"/>
1114− <image name="5" width="30" height="30"/>
1115− <image name="chat" width="30" height="30"/>
1116− </resources>
1117496</document>
GDproject/Constants.swift−28
@@ -6,7 +6,6 @@
66// Copyright © 2019 drHSE. All rights reserved.
77//
88
9−import UIKit
109/// constant for cell in posts NewsController.swift
1110let postCellId = "PostCell"
1211
@@ -42,30 +41,3 @@ let newsController = "NewsController"
4241
4342/// constant for switching to view controller for log in app
4443let logInController = "LogInController"
45−
46−/// constant for getting to messages
47−let messagesViewControllerId = "MessagesViewController"
48−
49−/// constant for displaying list of people to send message to
50−let peopleToWriteVC = "PeopleToWriteViewController"
51−
52−let dialogVC = "DialogViewController"
53−
54−let profileViewController = "ProfileViewController"
55−
56−let simplifiedChannelsList = "SimplifiedChannelsList"
57−
58−let channelViewControllerId = "ChannelViewController"
59−
60−let addToChannelVCId = "AddToChannelVC"
61−
62−let taggsSelectionViewController = "TaggsSelectionViewController"
63−
64−let dialogViewController = "DialogViewController"
65−
66−let tagsSuggestionController = "TagsSuggestionController"
67−
68−let chatInfoViewController = "ChatInfoViewController"
69−
70−let blueSystemColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)
71−
GDproject/Controller/ News and channels/AddToChannelVC.swiftdeleted−132
@@ -1,132 +0,0 @@
1−//
2−// AddToChannelVC.swift
3−// GDproject
4−//
5−// Created by cstore on 02/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−enum DataSourse{
12− case people, tags
13−}
14−
15−class AddToChannelVC: UITableViewController {
16−
17− var channel: Model.Channels?
18− weak var update: UpdatableChannel?
19−
20− // data sources for people and hashtags
21− var dataSourcePeople: [Model.Users] = Model.Channels.fullPeople
22−
23− var reloadtable: Bool = false {
24− didSet{
25− tableView.reloadData()
26− }
27− }
28−
29− var filteredDataSource = [Model.Users]()
30−
31− func filterContentForSearchText(_ searchText: String, scope: String = "All")
32− {
33− filteredDataSource = dataSourcePeople.filter { $0.fullName().lowercased().contains(searchText.lowercased()) }
34− tableView.reloadData()
35− }
36−
37− let searchC = UISearchController(searchResultsController: nil)
38−
39− override func viewDidLoad() {
40− super.viewDidLoad()
41−
42− navigationItem.title = "People"
43− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
44− self.navigationItem.searchController = searchC
45− navigationItem.largeTitleDisplayMode = .never
46− self.navigationItem.hidesSearchBarWhenScrolling = false
47− definesPresentationContext = true
48− searchC.searchResultsUpdater = self
49− searchC.obscuresBackgroundDuringPresentation = false
50− }
51−
52− override func viewWillDisappear(_ animated: Bool) {
53− super.viewWillDisappear(animated)
54− update?.updateChannel(with: channel!)
55− }
56− // MARK: - Table view data source
57−
58− override func numberOfSections(in tableView: UITableView) -> Int {
59− return 1
60− }
61−
62− var isFiltering: Bool {
63− return searchC.isActive && !searchBarIsEmpty()
64− }
65−
66− func searchBarIsEmpty() -> Bool {
67− return searchC.searchBar.text?.isEmpty ?? true
68− }
69−
70− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
71− if isFiltering {
72− return filteredDataSource.count
73− } else {
74− return dataSourcePeople.count
75− }
76− }
77−
78− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
79− {
80− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
81−
82− if isFiltering{
83− cell.textLabel?.text = filteredDataSource[indexPath.row].fullName()
84− if channel!.people.contains(filteredDataSource[indexPath.row].id) {
85− cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
86− } else {
87− cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
88− }
89− } else {
90− cell.textLabel?.text = dataSourcePeople[indexPath.row].fullName()
91− if channel!.people.contains(dataSourcePeople[indexPath.row].id) {
92− cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
93− } else {
94− cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
95− }
96− }
97−
98− cell.selectionStyle = .none
99−
100− return cell
101− }
102−
103− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
104− if let cell = tableView.cellForRow(at: indexPath) {
105− if isFiltering{
106− if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
107− let filtered = channel!.people.filter{ $0 != filteredDataSource[indexPath.row].id }
108− channel?.people = filtered
109− cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
110− } else {
111− channel?.people.append(filteredDataSource[indexPath.row].id)
112− cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
113− }
114− } else {
115− if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
116− let filtered = channel!.people.filter{ $0 != dataSourcePeople[indexPath.row].id }
117− channel?.people = filtered
118− cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
119− } else {
120− channel?.people.append(dataSourcePeople[indexPath.row].id)
121− cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
122− }
123− }
124− }
125− }
126−}
127−
128−extension AddToChannelVC : UISearchResultsUpdating {
129− func updateSearchResults(for searchController: UISearchController) {
130− filterContentForSearchText(searchController.searchBar.text!)
131− }
132−}
GDproject/Controller/ News and channels/ChannelController.swift+60−159
@@ -9,12 +9,7 @@
99import UIKit
1010
1111protocol DataDelegate {
12− func passData(for row: Int, channel: Model.Channels)
13−}
14−
15−enum ActiveTable {
16− case tags
17− case people
12+ func passData(for row: Int, channel: Channel)
1813}
1914
2015class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, UISearchBarDelegate
@@ -22,19 +17,14 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
2217 @IBOutlet weak var tableView: UITableView!
2318
2419 var index: Int?
25− var channel: Model.Channels?
20+ var channel: Channel?
2621 var myProtocol: DataDelegate?
2722
28− var fullTags: [String] = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
29−
30− var dataSourcePeople: [Model.Users] = []
31−
32− var dataSourceTags: [String] = []
23+ var dataSource: [String] = []
3324
34− var activeDataSource: ActiveTable = .people
25+ var fullPeople: [String] = ["Other Ann", "Other Ilya", "Other Kostya", "Pasha", "Valera"]
3526
36− // func to show preview of the current channel
37− var onShowingPreview: ((Model.Channels)->())?
27+ var fullTags: [String] = ["# happy", "# sad", "# meme", "# shershakov", "# pupsik"]
3828
3929 @IBOutlet weak var viewww: UIView!
4030
@@ -42,75 +32,23 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
4232
4333 override func viewDidLoad() {
4434 super.viewDidLoad()
45−
46− dataSourceTags = channel!.tags
47− setUpController()
48− tableView.reloadData()
49− }
50−
51− var reloadtable: Bool = false {
52− didSet{
53− tableView.reloadData()
54− }
55− }
56−
57− override func viewWillAppear(_ animated: Bool) {
58− super.viewWillAppear(animated)
59− Model.getUsers(for: channel!.people) { [weak self] (people) in
60− self?.dataSourcePeople = Array(people.values)
61− self?.reloadtable = true
62− }
63− }
64−
65− // TODO: update channel
66− override func viewWillDisappear(_ animated: Bool) {
67−
68− defer {
69− super.viewWillDisappear(animated)
70− }
71−
72− guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else {
73− if let _ = channel?.id { print("update")
74− Model.updateChannel(with: channel!)
75− } else { print("create")
76− //Model.createChannel(with: channel!)
77− }
78− return
79− }
80− // nou
81− }
82−
83− @objc func showPreview(){
84− if let channel = channel {
85− onShowingPreview?(channel)
86− }
87− }
88−
89− func setUpController(){
90−
91− // setting up the preview button for the editing or created channel
92− navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Preview", style: .done, target: self, action: #selector(showPreview))
93−
9435 tableView.delegate = self
9536 tableView.dataSource = self
37+ dataSource = channel!.people
9638 tableView.register(UITableViewCell.self, forCellReuseIdentifier: itemCellId)
9739 tableView.reloadData()
9840 textField.delegate = self
9941 searchBar.delegate = self
10042 searchBar.selectedScopeButtonIndex = 0
101−
102− navigationItem.title = channel?.name
103− textField.placeholder = channel?.name
104−
43+ navigationItem.title = channel?.title
44+ textField.placeholder = channel?.title
10545 textField.addTarget(self, action: #selector(changedText(_:)), for: .editingChanged)
10646 }
10747
108−
109−
11048 @objc func changedText(_ textField: UITextField){
11149 navigationItem.title = textField.text
112− channel?.name = textField.text!
113− // myProtocol?.passData(for: index!, channel: channel!)
50+ channel?.title = textField.text!
51+ myProtocol?.passData(for: index!, channel: channel!)
11452 }
11553
11654 func numberOfSections(in tableView: UITableView) -> Int {
@@ -118,76 +56,72 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
11856 }
11957
12058 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
121− switch activeDataSource {
122− case .people:
123− return dataSourcePeople.count
124− case .tags:
125− return dataSourceTags.count
126− }
59+ return dataSource.count
12760 }
12861
12962 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
130− if searchBar.isFirstResponder, let cell = tableView.cellForRow(at: indexPath)
131− {
63+ if searchBar.isFirstResponder {
64+ if let cell = tableView.cellForRow(at: indexPath)
65+ {
66+
13267 if cell.accessoryType == .none{
13368 switch searchBar.selectedScopeButtonIndex{
13469 case 0:
135− channel?.people.append(dataSourcePeople[indexPath.row].id)
70+ channel?.people.append(dataSource[indexPath.row])
13671 print("people = \(channel!.people)")
13772 case 1:
138− channel?.tags.append(dataSourceTags[indexPath.row])
139− print("hashtags = \(channel!.tags)")
73+ channel?.hashtags.append(dataSource[indexPath.row])
74+ print("hashtags = \(channel!.hashtags)")
14075 default:
14176 break
14277 }
78+
14379 cell.accessoryType = .checkmark
14480 } else {
14581 cell.accessoryType = .none
14682
14783 switch searchBar.selectedScopeButtonIndex{
14884 case 0:
149− let filtered = channel!.people.filter{ $0 != Model.Channels.fullPeople[indexPath.row].id }
150− channel?.people = filtered
85+ channel?.people = channel!.people.filter({ (s) -> Bool in
86+ !fullPeople[indexPath.row].contains(s)
87+ })
88+ // TODO: dataPass
15189 case 1:
152− let filtered = channel!.tags.filter{
153− !fullTags[indexPath.row].contains($0)
154− }
155− channel?.tags = filtered
90+ channel?.hashtags = channel!.hashtags.filter({ (s) -> Bool in
91+ !fullTags[indexPath.row].contains(s)
92+ })
93+ // TODO: dataPass
15694 default:
15795 break
15896 }
15997 }
160− }
161− else
162− {
163− switch activeDataSource{
164− case .people:
165− channel?.people.remove(at: indexPath.row)
166− case .tags:
167− channel?.tags.remove(at: indexPath.row)
16898 }
169−
99+ } else
100+ {
170101 tableView.beginUpdates()
171− switch activeDataSource{
172− case .people:
173− dataSourcePeople.remove(at: indexPath.row)
174− case .tags:
175− dataSourceTags.remove(at: indexPath.row)
102+ dataSource.remove(at: indexPath.row)
103+ switch searchBar.selectedScopeButtonIndex{
104+ case 0:
105+ channel?.people.remove(at: indexPath.row)
106+ // TODO: dataPass
107+ case 1:
108+ channel?.hashtags.remove(at: indexPath.row)
109+ // TODO: dataPass
110+ default:
111+ break
176112 }
177113 tableView.deleteRows(at: [indexPath], with: .none)
178114 tableView.endUpdates()
179115 }
180116 }
181117
182− func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
183− {
118+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
184119 let cell = tableView.dequeueReusableCell(withIdentifier: itemCellId, for: indexPath)
185120
186− cell.textLabel?.text = activeDataSource == .people ? "\(dataSourcePeople[indexPath.row].firstName) \(dataSourcePeople[indexPath.row].middleName) \(dataSourcePeople[indexPath.row].lastName)" : dataSourceTags[indexPath.row]
121+ cell.textLabel?.text = dataSource[indexPath.row]
187122 cell.selectionStyle = .none
188123
189− if activeDataSource == .tags && channel!.tags.contains(dataSourceTags[indexPath.row]) ||
190− activeDataSource == .people && channel!.people.contains(dataSourcePeople[indexPath.row].id)
124+ if channel!.hashtags.contains(dataSource[indexPath.row]) || channel!.people.contains(dataSource[indexPath.row])
191125 {
192126 cell.accessoryType = .checkmark
193127 } else {
@@ -213,7 +147,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
213147 {
214148 let view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 70))
215149
216− if activeDataSource == .tags {
150+ if flag {
217151 searchBar.selectedScopeButtonIndex = 1
218152 } else {
219153 searchBar.selectedScopeButtonIndex = 0
@@ -231,12 +165,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
231165
232166 func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
233167 if searchText.isEmpty {
234− switch activeDataSource {
235− case .people:
236− dataSourcePeople = Model.Channels.fullPeople
237− case .tags:
238− dataSourceTags = fullTags
239− }
168+ dataSource = searchBar.selectedScopeButtonIndex == 0 ? fullPeople : fullTags
240169 tableView.reloadData()
241170 } else {
242171 filterTableView(ind: searchBar.selectedScopeButtonIndex, text: searchText)
@@ -246,75 +175,47 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
246175 func filterTableView(ind: Int, text: String){
247176 switch ind {
248177 case 0:
249− dataSourcePeople = Model.Channels.fullPeople.filter {
250− let fullName = "\($0.firstName) \($0.middleName) \($0.lastName)"
251− return fullName.lowercased().contains(text.lowercased())
252− }
178+ dataSource = fullPeople.filter({ (s) -> Bool in
179+ s.lowercased().contains(text.lowercased())
180+ })
253181 tableView.reloadData()
254182 case 1:
255− dataSourceTags = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: text)
183+ dataSource = fullTags.filter({ (s) -> Bool in
184+ s.lowercased().contains(text.lowercased())
185+ })
256186 tableView.reloadData()
257187 default:
258188 break
259189 }
260190 }
261191
192+ var flag = false
193+
262194 func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
263− activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
264195 if searchBar.isFirstResponder {
265− switch activeDataSource{
266− case .people :
267− dataSourcePeople = Model.Channels.fullPeople
268− dataSourceTags = []
269− case .tags:
270− dataSourceTags = fullTags
271− dataSourcePeople = []
272− }
196+ dataSource = searchBar.selectedScopeButtonIndex == 0 ? fullPeople : fullTags
197+ flag = searchBar.selectedScopeButtonIndex == 0 ? false : true
273198 if (!(searchBar.text?.isEmpty ?? true))
274199 {
275200 filterTableView(ind: selectedScope, text: searchBar.text!)
276201 }
277202 tableView.reloadData()
278203 } else if !(searchBar.isFirstResponder){
279− switch activeDataSource{
280− case .people :
281− dataSourcePeople = channel!.people.map({ (item) -> Model.Users in
282− Model.Channels.fullPeopleDict[item]!
283− })
284− dataSourceTags = []
285− case .tags:
286− dataSourceTags = channel!.tags
287− dataSourcePeople = []
288− }
204+ dataSource = searchBar.selectedScopeButtonIndex == 0 ? channel!.people : channel!.hashtags
205+ flag = searchBar.selectedScopeButtonIndex == 0 ? false : true
289206 tableView.reloadData()
290207 }
291208 }
292209
293210 func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
294− switch activeDataSource{
295− case .people :
296− dataSourcePeople = channel!.people.map({ (item) -> Model.Users in
297− Model.Channels.fullPeopleDict[item]!
298− })
299− dataSourceTags = []
300− case .tags:
301− dataSourceTags = channel!.tags
302− dataSourcePeople = []
303− }
304− activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
211+ dataSource = searchBar.selectedScopeButtonIndex == 0 ? channel!.people : channel!.hashtags
212+ flag = searchBar.selectedScopeButtonIndex == 0 ? false : true
305213 tableView.reloadData()
306214 }
307215
308216 func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
309− switch activeDataSource{
310− case .people :
311− dataSourcePeople = Model.Channels.fullPeople
312− dataSourceTags = []
313− case .tags:
314− dataSourceTags = fullTags
315− dataSourcePeople = []
316− }
317− activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
217+ dataSource = searchBar.selectedScopeButtonIndex == 0 ? fullPeople : fullTags
218+ flag = searchBar.selectedScopeButtonIndex == 0 ? false : true
318219 tableView.reloadData()
319220 }
320221
GDproject/Controller/ News and channels/ChannelListController.swift+58−74
@@ -13,27 +13,15 @@ struct ChannelData{
1313 var subtitle = String()
1414}
1515
16−protocol ChannelListData: class {
17− func reloadData (with channels: [Model.Channels])
18−}
19−
2016// TODO: make search controller availiable
21−class ChannelListController: UITableViewController {
22−
23− // MARK: - Output -
24− var onChannelSelected: ((Model.Channels) -> Void)?
25− var onEditingModeBegins: ((Model.Channels, IndexPath)->Void)?
17+class ChannelListController: UITableViewController, DataDelegate {
2618
27− // MARK: - filter search controller
28− var filteredDataSource = [Model.Channels]()
19+ // MARK:- filter search controller
2920
30− var displayingChannel: Model.Channels?
21+ var filteredDataSource = [Channel]()
22+ var myProtocol: DataDelegate?
3123
32− var toReload: Bool = false {
33− didSet {
34− tableView.reloadData()
35− }
36− }
24+ var generalChannel: Channel = Channel(title: "General", subtitle: "All posts", hashtags: ["All"], people: ["All"], posts: [])
3725
3826 var isFiltering: Bool {
3927 return searchController.isActive && !searchBarIsEmpty()
@@ -45,73 +33,72 @@ class ChannelListController: UITableViewController {
4533
4634 func filterContentForSearchText(_ searchText: String, scope: String = "All")
4735 {
48− filteredDataSource = dataSource.filter({(keys : Model.Channels) -> Bool in
49− return keys.name.lowercased().contains(searchText.lowercased())
36+ filteredDataSource = ChannelListController.dataSource.filter({(keys : Channel) -> Bool in
37+ return keys.title.lowercased().contains(searchText.lowercased())
5038 })
5139
5240 tableView.reloadData()
5341 }
5442
55− func passData(for row: Int, channel: Model.Channels) {
56− // dataSource[row] = channel
43+ func passData(for row: Int, channel: Channel) {
44+ ChannelListController.dataSource[row].hashtags = channel.hashtags
45+ ChannelListController.dataSource[row].people = channel.people
46+ ChannelListController.dataSource[row].title = channel.title
47+ ChannelListController.dataSource[row].subtitle = channel.subtitle
5748 }
5849
5950 var searchController = UISearchController(searchResultsController: nil)
6051
6152 override func viewDidLoad() {
6253 super.viewDidLoad()
63−
64− Model.usersAllGet()
65−
6654 setUpNavigationBar()
6755 navigationItem.title = "Channels"
68− searchController.searchResultsUpdater = self
6956 searchController.obscuresBackgroundDuringPresentation = false
7057 searchController.searchBar.placeholder = "Search channel"
7158 navigationItem.searchController = searchController
72− definesPresentationContext = true
7359 }
7460
7561 func setUpNavigationBar(){
76− navigationItem.largeTitleDisplayMode = .always
7762 navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addChannel))]
7863 }
7964
80− override func viewDidAppear(_ animated: Bool)
65+ override func viewWillAppear(_ animated: Bool)
8166 {
82− super.viewDidAppear(animated)
83− searchController.isActive = false
84− askForUpdates()
85− }
86−
87− func askForUpdates(){
88− Model.channelsList { [weak self] (channels) in
89− self?.dataSource = [ChannelListController.generalChannel] + channels
90− self?.toReload = true
91− }
92− }
93−
94− override func viewWillAppear(_ animated: Bool) {
95− super.viewWillAppear(true)
96− //askForUpdates()
97− tabBarController?.tabBar.isHidden = false
67+ super.viewWillAppear(animated)
68+ tableView.reloadData()
9869 }
9970
10071 @objc func addChannel()
10172 {
102− // editing mode is on automatically
103− onEditingModeBegins?(Model.Channels(people: [], name: "Untitled", id: 0, tags: []),IndexPath(row: 1, section: 0))
104− }
105−
106− static let generalChannel = Model.Channels(people: [], name: "General", id: -1, tags: [])
107−
108− var dataSource : [Model.Channels] = [ ChannelListController.generalChannel ]
73+ // insertion
74+ tableView.beginUpdates()
75+ ChannelListController.dataSource.insert(Channel(title: "Untitled", subtitle: "No", hashtags: [], people: [], posts: []), at: 0)
76+ tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .none)
77+ tableView.endUpdates()
78+
79+ // editing mode is one automatically
80+ let vc = storyboard?.instantiateViewController(withIdentifier: channelControllerId) as! ChannelController
81+ vc.index = 0
82+ vc.myProtocol = self
83+ vc.channel = ChannelListController.dataSource[0]
84+ navigationController?.pushViewController(vc, animated: true)
85+ }
86+
87+ static var dataSource : [Channel] = [
88+ Channel(title: "Title", subtitle: "subtitle", hashtags: ["# sad", "# happy"], people: ["Seva", "Andrey"], posts: [Post(dataArray: [.text("Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard.")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05")]),
89+ Channel(title: "Title2", subtitle: "subtitle2", hashtags: ["# studyhard", "# university"], people: ["Pasha", "Olya", "Andrey", "Ilya"], posts:
90+ [
91+ Post(dataArray: [.text("L'avantage du Lorem Ipsum sur un texte générique comme 'Du texte. Du texte. Du texte.' est qu'il possède une distribution de lettres plus ou moins normale.")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05"),
92+ Post(dataArray: [.text("par accident, souvent intentionnellement (histoire d'y rajouter de petits clins d'oeil, voire des phrases embarassantes).")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05")
93+ ]),
94+ Channel(title: "Title3", subtitle: "subtitle3", hashtags: ["# lol", "# meme", "# hehe"], people: ["Superman"], posts: [Post(dataArray: [.text("Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié.")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05")])
95+ ]
10996
11097 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
11198 if isFiltering {
11299 return filteredDataSource.count
113100 } else {
114− return dataSource.count
101+ return ChannelListController.dataSource.count
115102 }
116103 }
117104
@@ -122,11 +109,11 @@ class ChannelListController: UITableViewController {
122109
123110
124111 if isFiltering{
125− cell.textLabel?.text = filteredDataSource[indexPath.row].name
126− cell.detailTextLabel?.text = filteredDataSource[indexPath.row].tags.reduce(String(), { (r, next) -> String in "\(r) \(next)" })
112+ cell.textLabel?.text = filteredDataSource[indexPath.row].title
113+ cell.detailTextLabel?.text = filteredDataSource[indexPath.row].subtitle
127114 } else {
128− cell.textLabel?.text = dataSource[indexPath.row].name
129− cell.detailTextLabel?.text = dataSource[indexPath.row].tags.reduce(String(), { (r, next) -> String in "\(r) \(next)" })
115+ cell.textLabel?.text = ChannelListController.dataSource[indexPath.row].title
116+ cell.detailTextLabel?.text = ChannelListController.dataSource[indexPath.row].subtitle
130117 }
131118
132119 return cell
@@ -134,35 +121,30 @@ class ChannelListController: UITableViewController {
134121
135122
136123 override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
137− switch indexPath.row {
138− case 0:
139− return false
140− default:
141− return true
142− }
124+ return true
143125 }
144126
145127 override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
146128 {
147− let editButton = UITableViewRowAction(style: .normal, title: "Edit") { [unowned self] (rowAction, indexPath) in
148− self.onEditingModeBegins?(self.dataSource[indexPath.row], indexPath)
129+
130+ let editButton = UITableViewRowAction(style: .normal, title: "Edit") { [weak self] (action, indexPath) in
131+ let vc = self?.storyboard?.instantiateViewController(withIdentifier: channelControllerId) as! ChannelController
132+ vc.index = indexPath.row
133+ vc.myProtocol = self!
134+ vc.channel = ChannelListController.dataSource[indexPath.row]
135+ self?.navigationController?.pushViewController(vc, animated: true)
149136 }
137+ editButton.backgroundColor = .green
150138
151− editButton.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
152139
153140 let deleteButton = UITableViewRowAction(style: .normal, title: "Delete") { [weak self] (action, indexPath) in
154−
155− Model.channelsDelete(by: self!.dataSource[indexPath.row].id!, completion: {
156− print("хз что тут делать при успехе")
157− })
158−
159141 self?.tableView.beginUpdates()
160− self?.dataSource.remove(at: indexPath.row)
142+ ChannelListController.dataSource.remove(at: indexPath.row)
161143 self?.tableView.deleteRows(at: [indexPath], with: .none)
162144 self?.tableView.endUpdates()
163145 }
146+ deleteButton.backgroundColor = .red
164147
165− deleteButton.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
166148
167149 return [editButton, deleteButton]
168150 }
@@ -170,9 +152,11 @@ class ChannelListController: UITableViewController {
170152 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
171153 {
172154 if isFiltering {
173− onChannelSelected?(filteredDataSource[indexPath.row])
155+ navigationController?.popViewController(animated: true)
156+ myProtocol?.passData(for: 0, channel: filteredDataSource[indexPath.row])
174157 } else {
175− onChannelSelected?(dataSource[indexPath.row])
158+ navigationController?.popViewController(animated: true)
159+ myProtocol?.passData(for: 0, channel: ChannelListController.dataSource[indexPath.row])
176160 }
177161 }
178162}
GDproject/Controller/ News and channels/ChannelViewController.swiftdeleted−208
@@ -1,208 +0,0 @@
1−//
2−// ChannelViewController.swift
3−// MessageApp
4−//
5−// Created by cstore on 02/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−protocol UpdatableName: class{
12− func updateName(with name: String)
13−}
14−
15−protocol UpdatableChannel: class{
16− func updateChannel(with channel: Model.Channels)
17−}
18−
19−class ChannelViewController: UITableViewController, UpdatableName, UpdatableChannel, TagsReceiver
20−{
21− var onChoosingHashTags: (([String]?)->())?
22−
23− var onChoosingPeople: ((Model.Channels?)->())?
24−
25− func receiveTags(tags: [String]) {
26− self.channel?.tags = tags
27− }
28−
29− func updateName(with name: String){
30− channel?.name = name
31− }
32−
33− func updateChannel(with channel: Model.Channels) {
34− self.channel = channel
35− }
36−
37− var channel: Model.Channels?
38−
39− // func to show preview of the current channel
40− var onShowingPreview: ((Model.Channels)->())?
41−
42− override func viewDidLoad()
43− {
44− super.viewDidLoad()
45− tableView.keyboardDismissMode = .onDrag
46− navigationItem.rightBarButtonItems = [ UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(showPreview)), self.editButtonItem]
47− navigationItem.largeTitleDisplayMode = .never
48− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
49− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "searchCell")
50− }
51−
52− override func viewWillAppear(_ animated: Bool) {
53− super.viewWillAppear(animated)
54− tableView.reloadData()
55− }
56−
57− override func viewWillDisappear(_ animated: Bool) {
58−
59− defer {
60− super.viewWillDisappear(animated)
61− }
62−
63− guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else
64− {
65− if let id = channel?.id, id != 0
66− {
67− Model.updateChannel(with: channel!)
68− } else {
69− Model.createChannel(with: channel!) {
70− [weak self] in
71− self?.showAlertOn(result: $0)
72− return
73− }
74− }
75− return
76− }
77− // nou
78− }
79−
80− @objc func showPreview()
81− {
82− if let channel = channel {
83− onShowingPreview?(channel)
84− }
85− }
86−
87− // MARK: - Table view data source
88−
89− override func numberOfSections(in tableView: UITableView) -> Int {
90− return 3
91− }
92−
93− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
94− switch section {
95− case 1:
96− return (channel?.people.count ?? 0) + 1
97− case 2:
98− return (channel?.tags.count ?? 0) + 1
99− default:
100− return 1
101− }
102− }
103−
104− override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
105− switch section {
106− case 1:
107− return "People"
108− case 2:
109− return "Tags"
110− default:
111− return "Title"
112− }
113− }
114−
115− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
116−
117− switch indexPath.section{
118− case 1 , 2:
119− return whichCell(tableView, cellForRowAt: indexPath)
120− default:
121− let cell = tableView.dequeueReusableCell(withIdentifier: "titleCell") as! TitleCell
122−
123− cell.fill(title: channel?.name)
124− cell.update = self
125−
126− return cell
127− }
128− }
129−
130− private func whichCell(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
131− {
132− let row = indexPath.row
133− let section = indexPath.section
134−
135− if row == 0
136− {
137− let cell = tableView.dequeueReusableCell(withIdentifier: "searchCell")!
138− cell.textLabel?.text = "Add more"
139− cell.accessoryType = .disclosureIndicator
140− return cell
141− }
142−
143− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
144−
145− if section == 1 {
146− cell.textLabel?.text = "👤 \(Model.Channels.fullPeopleDict[channel?.people[row-1] ?? 0]!.fullName())"
147− } else {
148− cell.textLabel?.text = "# \(channel!.tags[row-1])"
149− }
150−
151− return cell
152− }
153−
154− override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
155− {
156− if editingStyle == UITableViewCell.EditingStyle.delete
157− {
158− if indexPath.section == 1 {
159− channel?.people.remove(at: indexPath.row-1)
160− } else {
161− channel?.tags.remove(at: indexPath.row-1)
162− }
163− }
164−
165− tableView.reloadData()
166− }
167−
168− override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
169− if indexPath.row == 0 {
170− return false
171− }
172−
173− return true
174− }
175−
176− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
177− {
178− if indexPath.row == 0 && indexPath.section == 1
179− {
180− onChoosingPeople?(channel)
181− }
182−
183− if indexPath.row == 0 && indexPath.section == 2 {
184− onChoosingHashTags?(channel?.tags)
185− }
186− }
187−}
188−
189−
190−class TitleCell: UITableViewCell, UITextFieldDelegate {
191−
192− @IBOutlet weak var titleLabel: UITextField!
193−
194− weak var update: UpdatableName?
195−
196− override func awakeFromNib() {
197− super.awakeFromNib()
198− }
199−
200− func fill(title: String?){
201− titleLabel.text = title
202− titleLabel.addTarget(self, action: #selector(changedText(_:)), for: .editingChanged)
203− }
204−
205− @objc func changedText(_ textField: UITextField){
206− update?.updateName(with: textField.text!)
207− }
208−}
GDproject/Controller/ News and channels/FullPostController.swift+25−21
@@ -11,8 +11,7 @@ import TinyConstraints
1111
1212class FullPostController: UITableViewController {
1313
14− var post: Model.Posts?
15− var type: HeaderType = .NONE
14+ var post: Post?
1615
1716 override func viewDidLoad() {
1817 super.viewDidLoad()
@@ -21,14 +20,33 @@ class FullPostController: UITableViewController {
2120
2221 setUpNavigationBar()
2322 tableView.separatorStyle = .none
23+
24+
2425 }
2526
2627 func setUpNavigationBar(){
27− navigationItem.largeTitleDisplayMode = .never
28− navigationItem.title = "Post"
28+ navigationController?.navigationBar.prefersLargeTitles = false
29+ navigationItem.title = "\(post?.fromUser.login ?? "")"
30+ navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(self.options))]
2931 }
3032
31−
33+ @objc func options(){
34+ // drafts
35+ // saved
36+
37+ let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
38+ let editAction = UIAlertAction(title: "Send via message", style: .default)
39+ let shareAction = UIAlertAction(title: "Send via project", style: .default)
40+ let settingsAction = UIAlertAction(title: "Copy link", style: .default)
41+ let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
42+
43+ optionMenu.addAction(editAction)
44+ optionMenu.addAction(shareAction)
45+ optionMenu.addAction(settingsAction)
46+ optionMenu.addAction(cancelAction)
47+
48+ self.present(optionMenu, animated: true, completion: nil)
49+ }
3250 // MARK: - Table view data source
3351
3452 override func numberOfSections(in tableView: UITableView) -> Int {
@@ -65,7 +83,7 @@ class FullPostController: UITableViewController {
6583 case 0:
6684 return 1
6785 case 1:
68− return 0
86+ return post?.comments.count ?? 0
6987 default:
7088 return 0
7189 }
@@ -77,21 +95,7 @@ class FullPostController: UITableViewController {
7795
7896 let cell = tableView.dequeueReusableCell(withIdentifier: postCellId) as! PostViewCell
7997
80−
81− cell.fill(with: PostCellData.create(with: post!.body), true, post: post!)
82−
83− switch type {
84− case .NEWS:
85− cell.onUserDisplay = { [weak self] (id) in
86− let vc = self?.storyboard!.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
87− vc.idProfile = id
88−
89− self?.navigationController?.pushViewController(vc, animated: true)
90− }
91− default:
92− break
93− }
94−
98+ cell.fill(with: post!.dataArray, true, post: post!)
9599 cell.selectionStyle = .none
96100 return cell
97101 }
GDproject/Controller/ News and channels/NewPostViewController.swift+41−131
@@ -10,39 +10,17 @@ import UIKit
1010import Cartography
1111import Marklight
1212import TinyConstraints
13−import TaggerKit
14−// import WSTagsField
1513
16−class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
17−{
18− func receiveTags(tags: [String]) {
19− currentTags = tags
20− }
14+class NewPostViewController: UIViewController, UITextViewDelegate {
2115
2216 @IBOutlet weak var view1: UIView!
23−
24− var currentTags: [String] = []
25−
26− // We want the whole experience, let's create two TKCollectionViews
27− let productTags = TKCollectionView()
28−
29− @IBAction func chooseTags(_ sender: UIButton) {
30− let vc = storyboard?.instantiateViewController(withIdentifier: taggsSelectionViewController) as! TaggsSelectionViewController
31−
32− NewPostViewController.draft = textView.text
33− vc.receiver = self
34− vc.currentTags = currentTags
35−
36− navigationController?.pushViewController(vc, animated: true)
37− }
38−
39− // fileprivate let tagsField = WSTagsField()
4017 // Keep strong instance of the `NSTextStorage` subclass
4118 let textStorage = MarklightTextStorage()
4219
43− static var draft: String = ""
44− static var hashTagsDraft: [String] = [ ]
20+ weak var parentVC: NewsController?
21+ var myProtocol: NewPostDelegate?
4522
23+ static var draft: String = ""
4624 var textView: UITextView!
4725
4826 // buttons for attaching images
@@ -68,53 +46,17 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
6846 override func viewDidLoad()
6947 {
7048 super.viewDidLoad()
71− //createTimerForUpdates()
72−
7349 setUpMD()
7450 setUpTextView()
75− // setUpAccessoryView()
76− //setUpTagsView()
51+ setUpAccessoryView()
7752 }
78−
79− /* func setUpTagsView(){
80− tagsField.frame = viewForTags.bounds
81− viewForTags.addSubview(tagsField)
82−
83− // tagsField.translatesAutoresizingMaskIntoConstraints = false
84− // tagsField.heightAnchor.constraint(lessThanOrEqualToConstant: 150).isActive = true
85−
86− tagsField.cornerRadius = 3.0
87− tagsField.spaceBetweenLines = 10
88− tagsField.spaceBetweenTags = 10
89−
90− //tagsField.numberOfLines = 3
91− //tagsField.maxHeight = 100.0
92−
93− tagsField.layoutMargins = UIEdgeInsets(top: 2, left: 6, bottom: 2, right: 6)
94− tagsField.contentInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) //old padding
95−
96− tagsField.placeholder = "Enter a tag"
97− tagsField.placeholderColor = #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)
98− tagsField.placeholderAlwaysVisible = true
99− tagsField.backgroundColor = #colorLiteral(red: 0.937254902, green: 0.937254902, blue: 0.9568627451, alpha: 1)
100− tagsField.returnKeyType = .next
101− tagsField.delimiter = ""
102−
103− tagsField.textDelegate = self
104− tagsField.acceptTagOption = .space
105−
106− textFieldEvents()
107− }*/
10853
10954 override func viewWillAppear(_ animated: Bool) {
11055 super.viewWillAppear(animated)
11156
112− //navigationController?.navigationBar.prefersLargeTitles = false
113− navigationItem.largeTitleDisplayMode = .never
57+ navigationController?.navigationBar.prefersLargeTitles = false
11458 navigationItem.title = "New post"
11559 textView.text = NewPostViewController.draft
116− // tagsField.addTags(NewPostViewController.hashTagsDraft)
117−
11860 }
11961
12062 func setUpAccessoryView(){
@@ -141,7 +83,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
14183 func setUpTextView(){
14284 view.addConstraint(bottomTextViewConstraint)
14385 view1.addSubview(textView)
144− textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(8) + .right(8))
86+ textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(40+8) + .right(8))
14587
14688 if #available(iOS 11.0, *) {
14789 textView.smartDashesType = .no
@@ -206,11 +148,27 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
206148
207149 @objc func addMathBrackets()
208150 {
209− // nothing
151+ if textView.text.count != 0 && textView.text.last != "\n" {
152+ textView.insertText("\n\\[\n ")
153+ }
154+ else {
155+ textView.insertText("\\[\n ")
156+ }
157+
158+ if let selectedRange = textView.selectedTextRange
159+ {
160+ textView.insertText("\n\\]\n")
161+
162+ if let newPosition = textView.position(from: selectedRange.start, offset: 0)
163+ {
164+ // set the new position
165+ textView.selectedTextRange = textView.textRange(from: newPosition, to: newPosition)
166+ }
167+ }
210168 }
211169
212170 func setUpMD(){
213− textStorage.marklightTextProcessor.codeColor = UIColor.gray
171+ textStorage.marklightTextProcessor.codeColor = UIColor.orange
214172 textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
215173 textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
216174 textStorage.marklightTextProcessor.codeFontName = "Courier"
@@ -220,7 +178,6 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
220178 let layoutManager = NSLayoutManager()
221179
222180 // Assign the `UITextView`'s `NSLayoutManager` to the `NSTextStorage` subclass
223− //textStorage.addLayoutManager(textView.layoutManager)
224181 textStorage.addLayoutManager(layoutManager)
225182
226183 let textContainer = NSTextContainer()
@@ -229,30 +186,14 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
229186 textView = UITextView(frame: view.bounds, textContainer: textContainer)
230187 }
231188
232− var indexOfPost = 0
233189 // MARK:- new post
234190 @objc func newPost(){
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− }
191+ let p = Post(dataArray: [.text(textView.text)], from: User(name: "Сева", id: 5, fullName: "Сева Леонидович"), date: "12.01.19")
192+
250193
251− // NewPostViewController.draft = ""
252− // NewPostViewController.hashTagsDraft = []
253194 // adding row to uiTableView after adding new post
254− // myProtocol?.addPost(post: p)
255− // moveBackToParentVC?()
195+ myProtocol?.addPost(post: p)
196+ moveBackToParentVC()
256197 // somewhere here i will be sending server notifications about new post arrival
257198 }
258199
@@ -264,8 +205,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
264205 [weak self]
265206 _ in
266207 NewPostViewController.draft = self?.textView.text ?? ""
267− NewPostViewController.hashTagsDraft = self?.currentTags ?? []
268− self?.moveBackToParentVC?()
208+ self?.moveBackToParentVC()
269209 }
270210
271211 let deleteAction = UIAlertAction(title: "Delete draft", style: .destructive)
@@ -273,8 +213,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
273213 [weak self] (_)
274214 in
275215 NewPostViewController.draft = ""
276− NewPostViewController.hashTagsDraft = []
277− self?.moveBackToParentVC?()
216+ self?.moveBackToParentVC()
278217 }
279218
280219 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
@@ -291,7 +230,16 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
291230 actionSaveDraft()
292231 }
293232
294− var moveBackToParentVC: (()->())?
233+ func moveBackToParentVC(){
234+ let transition = CATransition()
235+ transition.duration = 0.5
236+ transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
237+ transition.type = CATransitionType.reveal
238+ transition.subtype = CATransitionSubtype.fromBottom
239+ navigationController?.view.layer.add(transition, forKey: nil)
240+ navigationController?.popViewController(animated: false)
241+ textView!.resignFirstResponder()
242+ }
295243
296244
297245 func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
@@ -304,42 +252,4 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
304252 rect.size.height = rect.size.height + textView.textContainerInset.bottom
305253 textView.scrollRectToVisible(rect, animated: animated)
306254 }
307−
308− /*fileprivate func textFieldEvents() {
309− tagsField.onDidAddTag = { _, _ in
310− print("onDidAddTag")
311− }
312−
313− tagsField.onDidRemoveTag = { _, _ in
314− print("onDidRemoveTag")
315− }
316−
317− tagsField.onDidChangeText = { _, text in
318− print("onDidChangeText")
319− }
320−
321− tagsField.onDidChangeHeightTo = { _, height in
322− print("HeightTo \(height)")
323− }
324−
325− tagsField.onDidSelectTagView = { _, tagView in
326− print("Select \(tagView)")
327− }
328−
329− tagsField.onDidUnselectTagView = { _, tagView in
330− print("Unselect \(tagView)")
331− }
332− }*/
333−}
334−
335−
336−extension NewPostViewController: UITextFieldDelegate {
337−
338− func textFieldShouldReturn(_ textField: UITextField) -> Bool {
339− /*if textField == tagsField {
340− textView.becomeFirstResponder()
341− }*/
342− return true
343− }
344−
345255}
GDproject/Controller/ News and channels/NewsController.swift+183−96
@@ -10,150 +10,237 @@ import UIKit
1010import TinyConstraints
1111import Cartography
1212
13−protocol UpdateableWithChannel: class {
14− var channel: Model.Channels? { get set }
15− func updateChannel(on channel: Model.Channels)
16−}
1713
18−protocol UpdateableWithUser: class {
19− var user: Model.Users? { get set }
14+protocol NewPostDelegate {
15+ func addPost(post: Post)
2016}
17+
2118// MARK:- Controller with posts and channels availiable.
2219// Search is availiable within every table (posts and channels). Has button-functionality for boths post and chnnels
23−class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWithChannel, UISearchResultsUpdating
20+class NewsController: UIViewController, UISearchControllerDelegate, UITableViewDelegate, UITableViewDataSource, DataDelegate, NewPostDelegate
2421{
25− func updateChannel(on channel: Model.Channels) {
26− self.channel = channel
27− news.currChannel = channel
28− decideWhatChannelDisplay()
22+
23+ func passData(for row: Int, channel: Channel) {
24+ news.dataSourse = channel.posts
25+ navigationItem.title = channel.title
2926 }
3027
31− var changedChannelName: ((String)->())?
28+ func addPost(post: Post) {
29+ news.dataSourse.insert(post, at: 0)
30+ }
3231
32+ var array = ["Faculty 1", "Faculty 2","Faculty 3","Faculty 4","Faculty 5","Faculty 6","Faculty 7","Faculty 8","Faculty 9","Faculty 10","Faculty 11","Faculty 12","Faculty 13","Faculty 14","Faculty 15","Faculty 16","Faculty 17","Faculty 18"]
33+
34+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
35+ return array.count
36+ }
37+
38+
39+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
40+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
41+
42+ cell.textLabel?.text = array[indexPath.row]
43+ return cell
44+ }
45+
46+ func presentSearchController(_ searchController: UISearchController) {
47+ print("here")
48+ setUpTableView()
49+ displayTableView() //setup
50+ // this is 0.3
51+ animateTable(some: true)
52+ }
53+
54+ func willDismissSearchController(_ searchController: UISearchController) {
55+ dismissTable()
56+ }
57+
3358 @IBOutlet weak var tableView: UITableView!
3459
35− var channel: Model.Channels?
36− var anonymousChannel: (users: [Int: Model.Users], posts: [Model.Posts])?
60+ var searchController = UISearchController(searchResultsController: nil)
3761
38− // MARK: - Output -
39− var onSelectChannel: (() -> Void)?
62+ var dataSourse: [Post] = [Post(dataArray: [.text("Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment, par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker. \n On sait depuis longtemps que travailler avec du texte lisible et contenant du sens est source de distractions, et empêche de se concentrer sur la mise en page elle-même. L'avantage du Lorem Ipsum sur un texte générique comme 'Du texte. Du texte. Du texte.' est qu'il possède une distribution de lettres plus ou moins normale, et en tout cas comparable avec celle du français standard. De nombreuses suites logicielles de mise en page ou éditeurs de sites Web ont fait du Lorem Ipsum leur faux texte par défaut, et une recherche pour 'Lorem Ipsum' vous conduira vers de nombreux sites qui n'en sont encore qu'à leur phase de construction. Plusieurs versions sont apparues avec le temps, parfois par accident, souvent intentionnellement (histoire d'y rajouter de petits clins d'oeil, voire des phrases embarassantes).")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05")]
4063
41− var searchController: UISearchController?
42−
4364 var news = NewsVC()
44− var type: HeaderType? = .NEWS
45−
46− var refreshContr = UIRefreshControl()
4765
4866 override func viewDidLoad()
4967 {
5068 super.viewDidLoad()
51−
52− let updater = TagsSuggestionController()
53− updater.delegate = self
54− searchController = UISearchController(searchResultsController: updater)
55− navigationItem.largeTitleDisplayMode = .always
56−
57− navigationController?.navigationBar.prefersLargeTitles = true
58− navigationItem.title = "Loading ..."
59− tableView.refreshControl = refreshContr
60− // Configure Refresh Control
61− refreshContr.addTarget(self, action: #selector(refreshPostsData(_:)), for: .valueChanged)
62−
6369 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
6470 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
6571
66− setUpSearchContr()
72+ searchController.delegate = self
73+ searchController.obscuresBackgroundDuringPresentation = false
6774
68− // navigationItem.
75+ news.dataSourse = dataSourse
6976 news.viewController = self
70− news.type = type == .NEWS ? .NEWS : type!
71− news.currChannel = channel
77+
78+
79+ tableView.delegate = news
80+ tableView.dataSource = news
81+ tableView.reloadData()
82+
83+ news.type = .NEWS
7284
7385 setUpNavigationItemsforPosts()
74− }
75−
76− func setUpSearchContr(){
77− searchController?.delegate = self
78− searchController?.obscuresBackgroundDuringPresentation = false
86+ searchController.searchBar.placeholder = "Search anything"
87+
7988 navigationItem.searchController = searchController
8089 definesPresentationContext = true
81− searchController?.searchResultsUpdater = self
82− searchController?.searchBar.placeholder = "Search tags"
90+
91+ setUpBanner()
92+ }
93+
94+
95+ var facultyTableView = UITableView()
96+
97+ func setUpTableView()
98+ {
99+ facultyTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
100+ facultyTableView.delegate = self
101+ facultyTableView.dataSource = self
102+ let screenSize: CGRect = UIScreen.main.bounds
103+
104+ let screenWidth = screenSize.width
105+ let screenHeight = screenSize.height
106+ facultyTableView.frame = CGRect(x: 0, y: 0, width: Int(screenWidth), height: Int(screenHeight))
83107 }
84108
85− @objc func refreshPostsData( _ ff: UIRefreshControl) {
86− decideWhatChannelDisplay()
109+ func displayTableView(){
110+
111+ // the most important line
112+ facultyTableView.translatesAutoresizingMaskIntoConstraints = false
113+ facultyTableView.backgroundColor = UIColor(white: 1, alpha: 1)
114+ view.addSubview(facultyTableView)
115+
116+ facultyTableView.isHidden = true
117+
118+ // now
119+ constrain(facultyTableView, view){
120+ tableView, view in
121+
122+ tableView.top == view.safeAreaLayoutGuide.top
123+ tableView.left == view.left
124+ tableView.right == view.right
125+ tableView.bottom == view.safeAreaLayoutGuide.bottom
126+ }
127+
128+ }
129+
130+ // animation of the table cells
131+ func animateTable(some: Bool){
132+ self.facultyTableView.reloadData()
133+ self.facultyTableView.isHidden = false
87134 }
88135
89− deinit {
90− print("news clear")
136+ func dismissTable() {
137+ self.facultyTableView.isHidden = true
91138 }
92139
93140 override func viewWillAppear(_ animated: Bool) {
94141 super.viewWillAppear(animated)
95− searchController?.isActive = false
96− // TODO:- display something if no posts are availiable
97−
98− decideWhatChannelDisplay()
99−
100− // tableView.reloadData()
101− }
102−
103− func decideWhatChannelDisplay(){
104−
105− switch type! {
106− case .NEWS, .NONE:
107− if let channel = channel, let id = channel.id, id != -1 {
108−
109− Model.getAnonymousChannel(by: channel) { [weak self] in
110− self?.news.dataSourse = $0.posts
111− self?.news.dictionary = $0.users
112− self?.refreshContr.endRefreshing()
113− self?.changedChannelName?(channel.name)
114− }
115−
116− } else {
117− Model.getLast { [weak self] in
118− self?.news.dataSourse = $0.posts
119− self?.news.dictionary = $0.users
120− self?.refreshContr.endRefreshing()
121− self?.changedChannelName?("General")
122− }
123− }
124− default:
125− refreshContr.endRefreshing()
126− break
127− }
128−
142+ print("hello")
143+ navigationController?.navigationBar.prefersLargeTitles = true
144+ tableView.reloadData()
129145 }
130146
131147 func setUpNavigationItemsforPosts(){
148+ navigationItem.title = "Posts"
149+ navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(self.writePost(_:)))]
132150 tableView.delegate = news
133151 tableView.dataSource = news
134152 tableView.reloadData()
135153 }
136154
137− func updateSearchResults(for searchController: UISearchController)
155+
156+
157+ @objc func writePost(_ barItem: UIBarButtonItem)
138158 {
139− let filteredData = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: searchController.searchBar.text?.lowercased() ?? "")
140−
141− // Apply the filtered results to the search results table.
142− if let resultsController = searchController.searchResultsController as? TagsSuggestionController {
143− resultsController.suggestions = filteredData
144− resultsController.tableView.reloadData()
145− }
159+ let vc = storyboard?.instantiateViewController(withIdentifier: "NewPostViewController") as! NewPostViewController
160+
161+ vc.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Post", style: .plain, target: vc, action: #selector(vc.newPost))
162+ vc.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: vc, action: #selector(vc.closeView))
163+
164+ vc.myProtocol = self
165+
166+ let transition = CATransition()
167+ transition.duration = 0.5
168+ transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
169+ transition.type = CATransitionType.moveIn
170+ transition.subtype = CATransitionSubtype.fromTop
171+ navigationController?.view.layer.add(transition, forKey: nil)
172+ navigationController?.pushViewController(vc, animated: false)
173+ }
174+
175+
176+
177+ // for animating the banner
178+ var topConstraint: NSLayoutConstraint?
179+
180+ let bannerView: UIView = {
181+ let view = UIView()
182+ view.backgroundColor = .blue
183+ view.layer.cornerRadius = 25.0
184+ view.clipsToBounds = true
185+ return view
186+ }()
187+
188+ let statusLabel: UILabel = {
189+ let label = UILabel()
190+ label.text = "-"
191+ label.textColor = .white
192+ label.textAlignment = .center
193+ return label
194+ }()
195+
196+ private func setUpBanner()
197+ {
198+ view.addSubview(bannerView)
199+ bannerView.addSubview(statusLabel)
200+ statusLabel.edgesToSuperview()
201+
202+ let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
203+
204+ bannerView.addGestureRecognizer(tap)
205+ topConstraint = NSLayoutConstraint(item: bannerView, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .top, multiplier: 1, constant: -300)
206+ view.addConstraint(topConstraint!)
207+
208+ bannerView.edgesToSuperview(excluding: [.bottom, .top, .left], insets: .right(20), usingSafeArea: true)
209+ bannerView.height(50)
210+ bannerView.width(50)
146211 }
147212
148− func willPresentSearchController(_ searchController: UISearchController) {
149− searchController.searchResultsController?.view.isHidden = false;
213+ // when table is scrolling no deletion is availiable
214+ @objc func handleTap(sender: UITapGestureRecognizer? = nil) {
215+ let indexPath = IndexPath(row: 0, section: 0)
216+ self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
217+// isBannerVisible = false
218+// changeConstraint(isVisible: false)
150219 }
151220
152− func didPresentSearchController(_ searchController: UISearchController) {
153− searchController.searchResultsController?.view.isHidden = false;
221+ // animation for banner
222+ func changeConstraint(isVisible: Bool){
223+ topConstraint?.constant = isVisible ? 50 : -300
224+
225+ UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
226+ self.view.layoutIfNeeded()
227+ }) { (completed) in
228+
229+ }
154230 }
155231
156− func didDismissSearchController(_ searchController: UISearchController) {
157− searchController.searchBar.text = ""
232+ var isBannerVisible: Bool = false
233+
234+ func scrollViewDidScroll(_ scrollView: UIScrollView) {
235+ print(scrollView.contentOffset.y)
236+ if scrollView.contentOffset.y >= 50 && !isBannerVisible{
237+ isBannerVisible = true
238+ changeConstraint(isVisible: true)
239+ }
240+
241+ if isBannerVisible && scrollView.contentOffset.y == 0{
242+ isBannerVisible = false
243+ changeConstraint(isVisible: false)
244+ }
158245 }
159246}
GDproject/Controller/ News and channels/NewsVC.swift+50−99
@@ -7,100 +7,78 @@
77//
88
99import UIKit
10−import MarkdownKit
1110
12−struct PostCellData{
13− var attributedData = NSAttributedString()
11+class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
1412
15− static func create(with attachments: [Model.Attachments]) -> NSAttributedString{
16− var markdown = ""
17−
18− attachments.forEach { (attachment) in markdown.append(attachment.markdown) }
19−
20− let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
21− markdownParser.enabledElements = .disabledAutomaticLink
22− markdownParser.code.font = UIFont(name: "Menlo", size: 16)
23− markdownParser.code.textBackgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
24− markdownParser.code.color = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
25−
26− return markdownParser.parse(markdown)
27− }
28−}
29−
30−class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
31−
32−
33− var onChannelDidChange: ((([Int: Model.Users],[Model.Posts]))->())?
34−
35− var onFullPost: ((HeaderType, Model.Posts)->())?
36−
37− var dictionary: [Int: Model.Users] = [:] {
38− didSet {
39−
40− dataSourse = dataSourse.map {
41− var copy = $0
42− copy.user = dictionary[$0.authorId]
43− return copy
44− }
45−
46− (viewController as? NewsController)?.tableView.reloadData()
47− (viewController as? ProfileViewController)?.tableView.reloadData()
48− }
49− }
50−
51− var currChannel : Model.Channels?
52−
53− var dataSourse: [Model.Posts] = [] {
54− didSet {
55− cellDataSourse = dataSourse.map { PostCellData(attributedData: PostCellData.create(with: $0.body)) }
56− }
57− }
58−
59− var cellDataSourse: [PostCellData] = []
13+ var dataSourse: [Post] = []
6014
6115 var type: HeaderType = .NONE
6216
63− weak var viewController: UIViewController?
17+ var viewController: UIViewController?
6418
6519 func numberOfSections(in tableView: UITableView) -> Int {
66− return 1
20+ switch type {
21+ case .NONE:
22+ return 1
23+ default:
24+ return 2
25+ }
6726 }
6827
6928 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
7029 {
71− onFullPost?(type, dataSourse[indexPath.row])
30+ tableView.deselectRow(at: indexPath, animated: true)
31+
32+ if indexPath.section == 1 && type == .NEWS || type == .NONE {
33+ let vc = viewController!.storyboard!.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
34+
35+ vc.post = dataSourse[indexPath.row]
36+ viewController!.navigationController!.pushViewController(vc, animated: true)
37+ }
38+ else if indexPath.section == 0 && type == .NEWS{
39+ let vc = viewController!.storyboard!.instantiateViewController(withIdentifier: channelListControllerId) as! ChannelListController
40+ vc.myProtocol = viewController as? NewsController
41+ viewController!.navigationController!.pushViewController(vc, animated: true)
42+ }
7243 }
7344
7445 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
75− return dataSourse.count
46+ switch type {
47+ case .NONE:
48+ return dataSourse.count
49+ default:
50+ switch section {
51+ case 0:
52+ return 1
53+ default:
54+ return dataSourse.count
55+ }
56+ }
7657 }
7758
7859 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
7960 {
80− let cell = tableView.dequeueReusableCell(withIdentifier: postCellId, for: indexPath) as! PostViewCell
81−
82− cell.fill(with: cellDataSourse[indexPath.row].attributedData, false, post: dataSourse[indexPath.row])
83−
8461 switch type {
85− case .NEWS:
86− cell.onUserDisplay = { [weak self] (id) in
87− let vc = self?.viewController!.storyboard!.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
88− vc.idProfile = id
89− self?.viewController!.navigationController!.pushViewController(vc, animated: true)
90− }
62+ case .NONE:
63+ let cell = tableView.dequeueReusableCell(withIdentifier: postCellId, for: indexPath) as! PostViewCell
9164
92− cell.onAnonymousChannelDisplay = {
93− [weak self] in
94− (self?.viewController as? UpdateableWithChannel)?.updateChannel(on: Model.Channels(people: [], name: $0, id: 0, tags: [$0]))
95− }
65+ cell.fill(with: dataSourse[indexPath.row].dataArray, false, post: dataSourse[indexPath.row])
66+ cell.selectionStyle = .none
67+ return cell
9668 default:
97− cell.onUserDisplay = { (id) in
98− print("tapped when profile is opened already \(id)")
69+ switch indexPath.section {
70+ case 0:
71+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
72+ cell.textLabel?.text = "List of channels"
73+ return cell
74+ default:
75+ let cell = tableView.dequeueReusableCell(withIdentifier: postCellId, for: indexPath) as! PostViewCell
76+
77+ cell.fill(with: dataSourse[indexPath.row].dataArray, false, post: dataSourse[indexPath.row])
78+ cell.selectionStyle = .none
79+ return cell
9980 }
10081 }
101−
102− cell.selectionStyle = .none
103− return cell
10482 }
10583
10684 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
@@ -110,37 +88,10 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
11088 func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
11189 return 100.0
11290 }
113−
114− var prevLast = -1
115−
116− func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
117− {
118− // pagination
119− if indexPath.row == cellDataSourse.count - 1 && prevLast != indexPath.row
120− {
121− if let ch = currChannel, let id = ch.id, id != -1 {
122− // check this!
123− Model.getAnonymousChannel(by: ch, exclusiveFrom: dataSourse.last?.id) { [weak self] in
124− self?.dataSourse.append(contentsOf: $0.posts)
125− $0.users.forEach { self?.dictionary[$0.key] = $0.value }
126− }
127−
128− } else {
129− // check this!
130− Model.getLast(on: 10, from: dataSourse.last?.id )
131− { [weak self] in
132− self?.dataSourse.append(contentsOf: $0.posts)
133− $0.users.forEach { self?.dictionary[$0.key] = $0.value }
134− }
135− }
136−
137− prevLast = indexPath.row
138− }
139− }
14091}
14192
93+
14294enum HeaderType {
14395 case NONE
14496 case NEWS
145− case ANONYMOUS
14697}
GDproject/Controller/ News and channels/PostViewCell.swift+38−63
@@ -8,21 +8,17 @@
88
99import UIKit
1010import Cartography
11+import MarkdownKit
1112import TinyConstraints
1213
1314class PostViewCell: UITableViewCell
1415{
15−
16− var onUserDisplay: ((Int)->())?
17−
18− var onAnonymousChannelDisplay: ((String)->())?
19−
20− let nameLabel: UIButton = {
21− let button = UIButton()
22− button.setTitleColor(.black, for: .normal)
23− button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
24− button.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left
25− return button
16+ let nameLabel: UILabel = {
17+ let label = UILabel()
18+ label.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
19+ label.text = "vbogomazova"
20+ label.font = UIFont.boldSystemFont(ofSize: 16)
21+ return label
2622 }()
2723
2824 let fullNameLabel: UILabel = {
@@ -33,7 +29,7 @@ class PostViewCell: UITableViewCell
3329 return label
3430 }()
3531
36− let timeLabel: UILabel = {
32+ let commentsLabel: UILabel = {
3733 let label = UILabel()
3834 label.font = UIFont.systemFont(ofSize: 12)
3935 label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
@@ -42,7 +38,6 @@ class PostViewCell: UITableViewCell
4238
4339 let shareButton: UIButton = {
4440 let button = UIButton(type: UIButton.ButtonType.detailDisclosure)
45− button.isHidden = true
4641 return button
4742 }()
4843
@@ -56,52 +51,50 @@ class PostViewCell: UITableViewCell
5651 fatalError("init(coder:) has not been implemented")
5752 }
5853
59− func createTextView(with text: NSAttributedString, _ isSelectable: Bool) -> UITextView
54+ func createTextView(with text: String) -> UITextView
6055 {
56+ let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
57+ let markdown = text
58+ markdownParser.enabledElements = .disabledAutomaticLink
59+ markdownParser.header.fontIncrease = 6
60+ markdownParser.code.textBackgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
61+
6162 let textView = UITextView()
6263 textView.isScrollEnabled = false
6364 textView.isEditable = false
64− if isSelectable {
65− //textView.isUserInteractionEnabled = false
66− textView.isSelectable = true
67− } else {
68− textView.isUserInteractionEnabled = false
69− }
70−
71− textView.attributedText = text
65+ textView.isUserInteractionEnabled = false
66+ textView.attributedText = markdownParser.parse(markdown)
7267 return textView
7368 }
7469
7570 var views: [UIView] = []
76− var post: Model.Posts?
71+ var data : [UIImage] = []
72+ var post: Post?
7773
78− func fill(with info: NSAttributedString, _ isFullVersoin: Bool, post: Model.Posts)
74+ func fill(with info: [Media], _ isFullVersoin: Bool, post: Post)
7975 {
8076 self.post = post
8177 // important
8278 contentView.subviews.forEach({ $0.removeFromSuperview() })
8379
80+ data = []
8481 views = []
85− views.append(createTextView(with: info, isFullVersoin))
86−
87− nameLabel.setTitle("\(post.user?.firstName ?? "") \(post.user?.lastName ?? "")", for: .normal)
88− nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
89− if let user = post.user{
90− fullNameLabel.text = "\(user.faculty.name)"
91− }
92− else {
93− fullNameLabel.text = "\(post.authorId)"
82+ for item in info.enumerated()
83+ {
84+ switch item.element
85+ {
86+ case .text(let text):
87+ views.append(createTextView(with: text))
88+ case .image(let images):
89+ self.data = images
90+ default:
91+ break
92+ }
9493 }
95−
9694 setUpInStackView(isFullVersoin)
9795 }
9896
99− var hashtags = [String]()
100−
10197 func setUpInStackView(_ full : Bool){
102−
103− hashtags = post!.tags
104−
10598 let nameStackView = UIStackView(arrangedSubviews: [nameLabel, fullNameLabel])
10699 nameStackView.axis = .vertical
107100 contentView.addSubview(nameStackView)
@@ -120,11 +113,11 @@ class PostViewCell: UITableViewCell
120113 scrollView.showsHorizontalScrollIndicator = false
121114
122115 var buttons: [UIButton] = []
123− for hash in hashtags {
116+ for hash in post!.hashtags {
124117 let button = UIButton()
125118 button.setTitle("#" + hash, for: .normal)
126− button.addTarget(self, action: #selector(setAnonymousChannel(on:)), for: .touchUpInside)
127− // button.addGestureRecognizer(longPressRecognizer)
119+ //button.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
120+ //button.layer.cornerRadius = 10
128121 button.titleLabel?.font = UIFont.monospacedDigitSystemFont(ofSize: 15, weight: .semibold)
129122 button.setTitleColor(#colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1), for: .normal)
130123 buttons.append(button)
@@ -150,13 +143,7 @@ class PostViewCell: UITableViewCell
150143 contentView.addSubview(mainView)
151144 mainView.edgesToSuperview(excluding: [.top, .bottom])
152145 mainView.topToBottom(of: nameStackView, offset: 5)
153−
154− // TODO:- change!!!!!!!!!!!!
155− if hashtags.isEmpty{
156− mainView.height(0)
157− } else {
158− mainView.height(30)
159− }
146+ mainView.height(30)
160147
161148 let stackView = MyStackView(arrangedSubviews: views)
162149 stackView.isFull = full
@@ -170,25 +157,13 @@ class PostViewCell: UITableViewCell
170157
171158 stackView.edgesToSuperview(excluding: [.top, .bottom], insets: .left(16) + .right(16))
172159
173− let commentsSharesStackView = UIStackView(arrangedSubviews: [ timeLabel, shareButton])
160+ let commentsSharesStackView = UIStackView(arrangedSubviews: [ commentsLabel, shareButton])
174161 contentView.addSubview(commentsSharesStackView)
175162
176− timeLabel.text = post!.convertDateFormatter()
177−
163+ commentsLabel.text = "14.02.19 в 23:00"
178164 commentsSharesStackView.axis = .horizontal
179165 commentsSharesStackView.distribution = .equalSpacing
180166 commentsSharesStackView.edgesToSuperview(excluding: .top, insets: .bottom(10) + .left(16) + .right(16))
181167 stackView.bottomToTop(of: commentsSharesStackView)
182168 }
183−
184− @objc func displayProfile(){
185− if let id = post?.authorId {
186− onUserDisplay?(id)
187− }
188− }
189−
190− @objc func setAnonymousChannel(on button: UIButton){
191− print("\(button.titleLabel?.text ?? "nothing")")
192− onAnonymousChannelDisplay?(String(button.titleLabel!.text!.dropFirst()))
193− }
194169}
GDproject/Controller/ News and channels/SimplifiedChannelsList.swiftdeleted−94
@@ -1,94 +0,0 @@
1−//
2−// SimplifiedChannelsList.swift
3−// GDproject
4−//
5−// Created by cstore on 13/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−
10−/// class for ADDing person to existing (or new) channel: like playlist in itunes
11−import UIKit
12−import TinyConstraints
13−
14−class SimplifiedChannelsList: UITableViewController {
15−
16− var user: Model.Users?
17−
18− var dataSource: [Model.Channels]?{
19− didSet{
20− tableView.reloadData()
21− }
22− }
23−
24− override func viewDidLoad() {
25− super.viewDidLoad()
26− setUpNavigationButtons()
27− navigationItem.title = "All channels"
28− navigationItem.largeTitleDisplayMode = .never
29− self.navigationItem.setHidesBackButton(true, animated:true)
30− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
31− }
32−
33− override func viewWillAppear(_ animated: Bool) {
34− Model.channelsList { [weak self] (channels) in
35− self?.dataSource = channels
36− }
37− }
38−
39− func setUpNavigationButtons(){
40− navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelAction))
41− }
42−
43− func completedActions(with channel: Model.Channels){
44− Model.updateChannel(with: channel)
45− cancelAction()
46− }
47−
48− @objc func cancelAction(){
49− let transition = CATransition()
50− transition.duration = 0.5
51− transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
52− transition.type = CATransitionType.reveal
53− transition.subtype = CATransitionSubtype.fromBottom
54− navigationController?.view.layer.add(transition, forKey: nil)
55− navigationController?.popViewController(animated: false)
56− }
57−
58− override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
59− let viewHeader = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 30))
60− viewHeader.backgroundColor = .white
61− let label = UILabel()
62−
63− label.text = "All channels"
64− label.font = UIFont.boldSystemFont(ofSize: 22)
65− label.textColor = .black
66−
67− viewHeader.addSubview(label)
68− label.edgesToSuperview(insets: .left(16))
69− return viewHeader
70− }
71−
72− override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
73− return 30
74− }
75−
76− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
77− return dataSource?.count ?? 0
78− }
79−
80− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
81− var channel = dataSource![indexPath.row]
82− channel.people.append(user!.id)
83− completedActions(with: channel)
84− }
85−
86− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
87− let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
88−
89− cell.textLabel?.text = dataSource![indexPath.row].name
90− cell.detailTextLabel?.text = "hello"
91−
92− return cell
93− }
94−}
GDproject/Controller/ News and channels/TaggsSelectionViewController.swiftdeleted−106
@@ -1,106 +0,0 @@
1−//
2−// TaggsSelectionViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 03/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TaggerKit
11−
12−protocol TagsReceiver: class {
13− func receiveTags(tags: [String])
14−}
15−
16−class TaggsSelectionViewController: UIViewController {
17−
18− @IBOutlet weak var addTagsTextField: TKTextField!
19−
20− @IBOutlet weak var searchContainerView: UIView!
21−
22− @IBOutlet weak var testContainer: UIView!
23−
24− // We want the whole experience, let's create two TKCollectionViews
25− let productTags = TKCollectionView()
26− let allTags = TKCollectionView()
27−
28− var currentTags: [String]?
29− weak var receiver: TagsReceiver?
30−
31− // MARK: - Lifecycle Methods
32− override func viewDidLoad() {
33− super.viewDidLoad()
34−
35− navigationItem.title = "Hashtags"
36− addTagsTextField.delegate = self
37− // Customisation example
38− // testCollection.customFont = UIFont.boldSystemFont(ofSize: 14) // Custom font
39− // testCollection.customCornerRadius = 14.0 // Corner radius of tags
40− // testCollection.customSpacing = 20.0 // Spacing between cells
41− // testCollection.customBackgroundColor = UIColor.red // Background of cells
42−
43−
44− // These are the tags already added by the user, give an aray of strings to the collection
45− if let tags = currentTags {
46− productTags.tags = tags
47− }
48− // These are intended to be all the tags the user has added in the app, which are going to be filtered
49− allTags.tags = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
50−
51− /*
52− We set this collection's action to .removeTag,
53− becasue these are supposed to be the tags the user has already added
54− */
55− productTags.action = .removeTag
56−
57−
58− // Set the current controller as the delegate of both collections
59− productTags.delegate = self
60− allTags.delegate = self
61−
62− // "testCollection" takes the tags sent by "searchCollection"
63− allTags.receiver = productTags
64−
65− // The tags in "searchCollection" are going to be added, so we set the action to addTag
66− allTags.action = .addTag
67−
68−
69− // Set the sender and receiver of the TextField
70− addTagsTextField.sender = allTags
71− addTagsTextField.receiver = productTags
72−
73− add(productTags, toView: testContainer)
74− add(allTags, toView: searchContainerView)
75− }
76−
77− override func viewWillDisappear(_ animated: Bool) {
78− super.viewWillDisappear(animated)
79− if let receiver = receiver{
80− receiver.receiveTags(tags: productTags.tags)
81− }
82− }
83−
84− /*
85− These methods come from UIViewController now conforming to TKCollectionViewDelegate,
86− You use these to do whatever you want when a tag is added or removed (e.g. save to file, etc)
87− */
88− override func tagIsBeingAdded(name: String?) {
89− // Example: save testCollection.tags to UserDefault
90− print("added \(name!)")
91− }
92−
93− override func tagIsBeingRemoved(name: String?) {
94− print("removed \(name!)")
95− }
96−}
97−
98−// textField deletage to close keyboard on return
99−extension TaggsSelectionViewController: UITextFieldDelegate
100−{
101− func textFieldShouldReturn(_ textField: UITextField) -> Bool
102− {
103− self.view.endEditing(true)
104− return false
105− }
106−}
GDproject/Controller/ News and channels/TagsSuggestionController.swiftdeleted−52
@@ -1,52 +0,0 @@
1−//
2−// AnonimousChannelController.swift
3−// GDproject
4−//
5−// Created by cstore on 20/04/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class TagsSuggestionController: UITableViewController
12−{
13− weak var delegate: UpdateableWithChannel?
14−
15− var suggestions = [String]()
16− var channel: Model.Channels?
17−
18− override func viewDidLoad()
19− {
20− super.viewDidLoad()
21− if let tree = Model.hashTagTree {
22− suggestions = CompletionTree.getCompletion(tree: tree, word: "")
23− print(suggestions)
24− }
25− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
26− tableView.reloadData()
27− }
28−
29− override func numberOfSections(in tableView: UITableView) -> Int {
30− return 1
31− }
32−
33− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
34− return suggestions.count
35− }
36−
37− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
38− {
39− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
40− cell.textLabel?.text = suggestions[indexPath.row]
41−
42− return cell
43− }
44−
45− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
46− {
47− channel = Model.Channels(people: [], name: "\(self.suggestions[indexPath.row])", id: 0, tags: [self.suggestions[indexPath.row]])
48−
49− delegate?.updateChannel(on: channel!)
50− self.dismiss(animated: true)
51− }
52−}
GDproject/Controller/Coordinators/ApplicationCoordinator.swiftdeleted−69
@@ -1,69 +0,0 @@
1−//
2−// ApplicationCoordinator.swift
3−// RxSwift
4−//
5−// Created by cstore on 04/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import Foundation
10−import UIKit
11−
12−
13−
14−fileprivate enum LaunchInstructor {
15− case main, auth
16−
17− static func configure(
18− isAutorized: Bool = DataStorage.standard.isLoggedIn) -> LaunchInstructor {
19−
20− if isAutorized{
21− return .main
22− } else {
23− return .auth
24− }
25− }
26−}
27−
28−final class ApplicationCoordinator: BaseCoordinator{
29− private var window: UIWindow!
30−
31− init(window: UIWindow) {
32− self.window = window
33− }
34−
35− private var instructor: LaunchInstructor {
36− return LaunchInstructor.configure()
37− }
38−
39− override func start() {
40− switch instructor {
41− case .auth: runAuthFlow()
42− case .main: runMainFlow()
43− }
44− }
45−
46− private func runAuthFlow() {
47− let coordinator = LogInCoordinator(window: window)
48− coordinator.didEndFlow = { [weak self, weak coordinator] in
49− self?.start()
50− self?.removeDependency(coordinator)
51− }
52− addDependency(coordinator)
53− coordinator.start()
54− }
55−
56− private func runMainFlow() {
57− let storyboard = UIStoryboard(name: "Main", bundle: nil)
58− let tabBar = storyboard.instantiateViewController(withIdentifier: "TabbarController") as! TabbarController
59− let coordinator = TabBarCoordinator(tabbarView: tabBar, window: window!)
60−
61− coordinator.didEndFlow = { [weak self, weak coordinator] in
62− self?.start()
63− self?.removeDependency(coordinator)
64− }
65−
66− addDependency(coordinator)
67− coordinator.start()
68− }
69−}
GDproject/Controller/Coordinators/BaseCoordinator.swiftdeleted−47
@@ -1,47 +0,0 @@
1−//
2−// BaseCoordinator.swift
3−// RxSwift
4−//
5−// Created by cstore on 02/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import Foundation
10−import UIKit
11−
12−protocol Coordinator: class {
13− func start()
14−}
15−
16−class BaseCoordinator: Coordinator {
17−
18− var childCoordinators: [Coordinator] = []
19−
20− func start() {
21−
22− }
23−
24− // add only unique object
25− func addDependency(_ coordinator: Coordinator) {
26− guard !childCoordinators.contains(where: { $0 === coordinator }) else { return }
27− childCoordinators.append(coordinator)
28− }
29−
30− func removeDependency(_ coordinator: Coordinator?) {
31− guard
32− childCoordinators.isEmpty == false,
33− let coordinator = coordinator
34− else { return }
35−
36− // Clear child-coordinators recursively
37− if let coordinator = coordinator as? BaseCoordinator, !coordinator.childCoordinators.isEmpty {
38− coordinator.childCoordinators
39− .filter({ $0 !== coordinator })
40− .forEach({ coordinator.removeDependency($0) })
41− }
42− for (index, element) in childCoordinators.enumerated() where element === coordinator {
43− childCoordinators.remove(at: index)
44− break
45− }
46− }
47−}
GDproject/Controller/Coordinators/ChannelsCoordinator.swiftdeleted−139
@@ -1,139 +0,0 @@
1−//
2−// ChannelsCoordinator.swift
3−// RxSwift
4−//
5−// Created by cstore on 03/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import Foundation
10−import UIKit
11−import Pulley
12−
13−class ChannelsCoordinator: BaseCoordinator{
14− let storyboard = UIStoryboard(name: "Main", bundle: nil)
15− private weak var navigationController: UINavigationController?
16−
17− init(nc: UINavigationController) {
18− self.navigationController = nc
19− navigationController?.navigationItem.largeTitleDisplayMode = .always
20− }
21−
22− override func start() {
23− show()
24− }
25−
26− private func show() {
27−
28− let channels = storyboard.instantiateViewController(withIdentifier: channelListControllerId) as! ChannelListController
29−
30− channels.onChannelSelected = { [unowned self]
31− (channel) in
32− self.navigationController?.pushViewController(self.presentNewsController(with: channel), animated: true)
33− }
34−
35− channels.askForUpdates()
36−
37− channels.onEditingModeBegins = { [unowned self] (channel, indexPath) in
38− let vc = self.presentChannelController(with: channel)
39− self.navigationController?.pushViewController(vc, animated: true)
40− vc.tabBarController?.tabBar.isHidden = true
41− }
42−
43− let nc = presentNewsController()
44− navigationController?.setViewControllers([channels, nc], animated: false)
45− }
46−
47− /// Function that presents channel controller
48− ///
49− /// - Parameter channel: channel that needs to be displayed
50− func presentChannelController(with channel: Model.Channels? = nil) -> ChannelViewController {
51− let mainContentVC = storyboard.instantiateViewController(withIdentifier: channelViewControllerId) as! ChannelViewController
52−
53− // to show preview we need to instantiate newsController but with different functionality
54− mainContentVC.onShowingPreview = { [weak mainContentVC, unowned self] ch in
55− let vc = self.presentNewsController(with: ch, previewMode: true)
56− mainContentVC?.navigationController?.pushViewController(vc, animated: true)
57− }
58−
59− // to go for choosing hashtags
60− mainContentVC.onChoosingHashTags = { [weak mainContentVC, unowned self] ch in
61− let vc = self.storyboard.instantiateViewController(withIdentifier: taggsSelectionViewController) as! TaggsSelectionViewController
62−
63− vc.currentTags = ch
64− vc.receiver = mainContentVC
65−
66− self.navigationController?.pushViewController(vc, animated: true)
67− }
68−
69− mainContentVC.onChoosingPeople = { [weak mainContentVC, unowned self] channel in
70− let vc = self.storyboard.instantiateViewController(withIdentifier: addToChannelVCId) as! AddToChannelVC
71−
72− vc.channel = channel
73− vc.update = mainContentVC
74−
75− self.navigationController?.pushViewController(vc, animated: true)
76− }
77−
78− mainContentVC.channel = channel
79− return mainContentVC
80− }
81−
82− func presentNewsController(with channel: Model.Channels? = nil, previewMode: Bool = false) -> NewsController
83− {
84− let mainContentVC = storyboard.instantiateViewController(withIdentifier: newsController) as! NewsController
85− mainContentVC.channel = channel
86−
87− if !previewMode {
88− mainContentVC.news.onFullPost = {
89− [weak self] (type,post) in
90−
91− let vc = self?.storyboard.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
92− vc.type = type
93− vc.post = post
94− self?.navigationController!.pushViewController(vc, animated: true)
95− }
96−
97− mainContentVC.news.onChannelDidChange = {
98− print("anon with \($0.0.count) users")
99− }
100−
101− mainContentVC.navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(writePost(_:)))
102− ]
103− }
104−
105− mainContentVC.changedChannelName = {
106− [weak mainContentVC] (title) in mainContentVC?.navigationItem.title = title
107− }
108−
109− return mainContentVC
110− }
111−
112− @objc private func writePost(_ barItem: UIBarButtonItem)
113− {
114− let vc = storyboard.instantiateViewController(withIdentifier: "NewPostViewController") as! NewPostViewController
115−
116− vc.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Post", style: .plain, target: vc, action: #selector(vc.newPost))
117− vc.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: vc, action: #selector(vc.closeView))
118−
119− let transition = CATransition()
120− transition.duration = 0.5
121− transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
122− transition.type = CATransitionType.moveIn
123− transition.subtype = CATransitionSubtype.fromTop
124− navigationController?.view.layer.add(transition, forKey: nil)
125− navigationController?.pushViewController(vc, animated: false)
126−
127− vc.moveBackToParentVC = {
128− [weak self] in
129−
130− let transition = CATransition()
131− transition.duration = 0.5
132− transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
133− transition.type = CATransitionType.reveal
134− transition.subtype = CATransitionSubtype.fromBottom
135− self?.navigationController?.view.layer.add(transition, forKey: nil)
136− self?.navigationController?.popViewController(animated: false)
137− }
138− }
139−}
GDproject/Controller/Coordinators/LogInCoordinator.swiftdeleted−70
@@ -1,70 +0,0 @@
1−//
2−// LogInCoordinator.swift
3−// RxSwift
4−//
5−// Created by cstore on 01/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class LogInCoordinator: BaseCoordinator {
12−
13− let storyboard = UIStoryboard(name: "Main", bundle: nil)
14−
15− var didEndFlow: (()->())?
16− var window: UIWindow!
17− var navigationController: UINavigationController?
18−
19− init(window: UIWindow) {
20− self.window = window
21− self.window?.rootViewController = UINavigationController()
22− self.navigationController = window.rootViewController as? UINavigationController
23− }
24−
25− override func start(){
26− let logInVC = LogInViewController()
27− logInVC.authenticate = { [weak self, weak logInVC] (email) in
28−
29− DataStorage.standard.setEmail(email: email)
30− Model.authenticate(with: email) { [weak self]
31− (authStatus) in
32−
33− print(authStatus.userStatus)
34−
35− if (authStatus.userStatus == "invalid") {
36− logInVC?.presentAlertInvalidCode()
37− }
38− else if (authStatus.userStatus == "canRegister") { // register form
39− self?.presentRegisterVC()
40− } else { // validation code
41− self?.presentViewControllerForCodeInput()
42− }
43− }
44− }
45−
46− navigationController?.pushViewController(logInVC, animated: false)
47− }
48−
49− func presentViewControllerForCodeInput()
50− {
51− let vc = storyboard.instantiateViewController(withIdentifier: "CodeViewController") as! CodeViewController
52− self.navigationController?.pushViewController(vc, animated: true)
53− vc.onSuccessLogIn = {
54− [weak self] in self?.didEndFlow?()
55− }
56− }
57−
58− func presentRegisterVC(){
59−
60− let vc1 = storyboard.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
61−
62− vc1.onRegistration = { [weak self] in
63− self?.presentViewControllerForCodeInput()
64− }
65−
66− self.navigationController?.pushViewController(vc1, animated: true)
67− }
68−
69−
70−}
GDproject/Controller/Coordinators/MessagesCoordinator.swiftdeleted−87
@@ -1,87 +0,0 @@
1−//
2−// MessagesCoordinator.swift
3−// GDproject
4−//
5−// Created by cstore on 01/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−
10−import Foundation
11−import UIKit
12−
13−class MessagesCoordinator: BaseCoordinator {
14−
15− var didEndSession: (()->())?
16−
17− let storyboard = UIStoryboard(name: "Main", bundle: nil)
18− private weak var navigationController: UINavigationController?
19−
20− init(nc: UINavigationController) {
21− self.navigationController = nc
22− }
23−
24− override func start() {
25− show()
26− }
27−
28− private func show(){
29− let vc = storyboard.instantiateViewController(withIdentifier: messagesViewControllerId) as! MessagesViewController
30−
31− // choose person to write message to
32− vc.onUserDisplayList = { [weak vc, unowned self] in
33−
34− let newVC = self.storyboard.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
35−
36− newVC.whatToDoWithSelection = { [weak newVC, weak self] people in
37− newVC?.navigationController?.popViewController(animated: true)
38−
39− // detect is it a user or group dialog
40− let count = people.count
41− if count == 1 {
42−
43− let user = people.first!.key
44− let createdDialog = Model.Dialog.userChat(Model.UserChat(user: user))
45−
46− let vc = DialogViewController()
47− vc.users = Model.Channels.fullPeopleDict
48− vc.dialog = createdDialog
49− self?.navigationController?.pushViewController(vc, animated: true)
50−
51− } else {
52− var group = Model.Group(users: people, name: "Untitled", id: 0)
53− group.users[DataStorage.standard.getUserId()] = Model.UserPermission(isAdmin: true)
54−
55− Model.createGroupChat(from: group, completion: { [weak self] id in
56−
57− let newVC1 = DialogViewController()
58− group.id = id
59− newVC1.users = Model.Channels.fullPeopleDict
60− newVC1.dialog = Model.Dialog.groupChat(Model.GroupChat(group: group))
61− self?.navigationController?.pushViewController(newVC1, animated: true)
62− })
63− }
64− }
65−
66− vc?.navigationController?.pushViewController(newVC, animated: true)
67− }
68−
69− vc.onDialogDisplay = { [weak vc] in
70−
71− let newVC = DialogViewController()
72− newVC.dialog = $0.dialog
73− newVC.users = $0.users
74− newVC.onUserDisplay = { [weak self] id in
75−
76− let vc = self?.storyboard.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
77− vc.idProfile = id
78− self?.navigationController!.pushViewController(vc, animated: true)
79−
80− }
81−
82− vc?.navigationController?.pushViewController(newVC, animated: true)
83− }
84−
85− navigationController?.viewControllers = [vc]
86− }
87−}
GDproject/Controller/Coordinators/ProfileCoordinator.swiftdeleted−60
@@ -1,60 +0,0 @@
1−//
2−// ProfileCoordinator.swift
3−// RxSwift
4−//
5−// Created by cstore on 02/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import Foundation
10−import UIKit
11−
12−class ProfileCoordinator: BaseCoordinator {
13−
14− var didEndSession: (()->())?
15−
16− private weak var navigationController: UINavigationController?
17−
18− init(nc: UINavigationController) {
19− self.navigationController = nc
20− }
21−
22− override func start() {
23− show()
24− }
25−
26− private func show() {
27− let storyboard = UIStoryboard(name: "Main", bundle: nil)
28− let profile = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
29−
30− profile.logOut = {
31− Model.logout() {
32− [weak self] in
33−
34− DataStorage.standard.setIsLoggedIn(value: false, with: 0)
35− self?.didEndSession?()
36− }
37− }
38−
39− profile.deleteAllSessions = {
40− Model.deactivateAll() {
41− [weak self] in
42−
43− DataStorage.standard.setIsLoggedIn(value: false, with: 0)
44− self?.didEndSession?()
45− }
46− }
47−
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
53−
54− self?.navigationController?.pushViewController(vc, animated: true)
55− }
56−
57−
58− navigationController?.setViewControllers([profile], animated: false)
59− }
60−}
GDproject/Controller/Coordinators/TabbarController.swiftdeleted−50
@@ -1,50 +0,0 @@
1−//
2−// TabbarController.swift
3−// RxSwift
4−//
5−// Created by cstore on 03/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import Foundation
10−import UIKit
11−
12−protocol TabbarView: class {
13− var onChannelsFlowSelect: ((UINavigationController) -> ())? { get set }
14− var onProfileFlowSelect: ((UINavigationController) -> ())? { get set }
15− var onMessagesFlowSelect: ((UINavigationController) -> ())? { get set }
16− var onViewDidLoad: ((UINavigationController) -> ())? { get set }
17−}
18−
19−final class TabbarController: UITabBarController, UITabBarControllerDelegate, TabbarView {
20−
21−
22− var onChannelsFlowSelect: ((UINavigationController) -> ())?
23− var onProfileFlowSelect: ((UINavigationController) -> ())?
24− var onMessagesFlowSelect: ((UINavigationController) -> ())?
25−
26− var onViewDidLoad: ((UINavigationController) -> ())?
27−
28− override func viewDidLoad() {
29− super.viewDidLoad()
30−
31− delegate = self
32− if let controller = customizableViewControllers?.first as? UINavigationController {
33− onViewDidLoad?(controller)
34− }
35− }
36−
37− func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController)
38− {
39−
40− guard let controller = viewControllers?[selectedIndex] as? UINavigationController else { return }
41−
42− if selectedIndex == 0 {
43− onChannelsFlowSelect?(controller)
44− } else if selectedIndex == 2 {
45− onProfileFlowSelect?(controller)
46− } else {
47− onMessagesFlowSelect?(controller)
48− }
49− }
50−}
GDproject/Controller/Coordinators/TabbarCoordinator.swiftdeleted−68
@@ -1,68 +0,0 @@
1−//
2−// TabBarCoordinator.swift
3−// RxSwift
4−//
5−// Created by cstore on 02/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import Foundation
10−import UIKit
11−
12−
13−class TabBarCoordinator: BaseCoordinator {
14−
15− var didEndFlow: (()->())?
16−
17− private let tabbarView: TabbarView
18− private weak var window: UIWindow?
19−
20− init(tabbarView: TabbarView, window: UIWindow) {
21− self.tabbarView = tabbarView
22− self.window = window
23− }
24−
25− override func start() {
26− tabbarView.onViewDidLoad = runChannelsFlow()
27− tabbarView.onChannelsFlowSelect = runChannelsFlow()
28− tabbarView.onProfileFlowSelect = runProfileFlow()
29− tabbarView.onMessagesFlowSelect = runMessagesFlow()
30− window?.rootViewController = tabbarView as! TabbarController
31− }
32−
33− private func runChannelsFlow() -> ((UINavigationController) -> ())
34− {
35− return { [unowned self] navController in
36− if navController.viewControllers.isEmpty == true {
37− let channelCoordinator = ChannelsCoordinator(nc: navController)
38− self.addDependency(channelCoordinator)
39− channelCoordinator.start()
40− }
41− }
42− }
43−
44− private func runMessagesFlow() -> ((UINavigationController) -> ()){
45− return { [unowned self] navController in
46− if navController.viewControllers.isEmpty == true {
47− let messagesCoordinator = MessagesCoordinator(nc: navController)
48− self.addDependency(messagesCoordinator)
49− messagesCoordinator.start()
50− }
51− }
52− }
53−
54− private func runProfileFlow() -> ((UINavigationController) -> ())
55− {
56− return { [unowned self] navController in
57− if navController.viewControllers.isEmpty == true {
58− let profileCoordinator = ProfileCoordinator(nc: navController)
59− profileCoordinator.didEndSession = { [weak self, weak profileCoordinator] in
60− self?.removeDependency(profileCoordinator)
61− self?.didEndFlow?()
62− }
63− self.addDependency(profileCoordinator)
64− profileCoordinator.start()
65− }
66− }
67− }
68−}
GDproject/Controller/Log In/CodeViewController.swiftdeleted−144
@@ -1,144 +0,0 @@
1−//
2−// CodeViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−
12−class CodeViewController: UIViewController {
13−
14− @IBOutlet weak var f1: UITextField!
15− @IBOutlet weak var f2: UITextField!
16− @IBOutlet weak var f3: UITextField!
17− @IBOutlet weak var f4: UITextField!
18− @IBOutlet weak var f5: UITextField!
19− @IBOutlet weak var f6: UITextField!
20−
21− var loading = UIActivityIndicatorView(style: .gray)
22−
23− var onSuccessLogIn: (()->())?
24−
25− override func viewDidLoad() {
26− super.viewDidLoad()
27− setUpConstraint()
28−
29− navigationItem.title = DataStorage.standard.getEmail()
30−
31− f1.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
32− f2.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
33− f3.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
34− f4.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
35− f5.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
36− f6.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
37− }
38−
39− override func viewWillDisappear(_ animated: Bool) {
40− super.viewWillDisappear(animated)
41−
42− loading.stopAnimating()
43− }
44−
45− override func viewWillAppear(_ animated: Bool) {
46− super.viewWillAppear(animated)
47−
48− f1.becomeFirstResponder()
49− }
50−
51− @objc func textFiledDidChange(textField: UITextField) {
52− let text = textField.text
53−
54− // only 1 char
55− if text?.utf16.count == 1 {
56− switch textField {
57− case f1:
58− f2.becomeFirstResponder()
59− case f2:
60− f3.becomeFirstResponder()
61− case f3:
62− f4.becomeFirstResponder()
63− case f4:
64− f5.becomeFirstResponder()
65− case f5:
66− f6.becomeFirstResponder()
67− case f6:
68− f6.resignFirstResponder()
69− default:
70− break
71− }
72− }
73− }
74−
75−
76− func presentAlertInvalidData(with text: String)
77− {
78− let alert = UIAlertController(title: "Invalid code", message: text, preferredStyle: .alert)
79− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
80− self.present(alert, animated: true, completion: nil)
81−
82− loading.stopAnimating()
83− }
84−
85− @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
86−
87− @IBAction func whereToGoNext(_ sender: UIButton)
88− {
89− guard let f1t = f1.text, let f2t = f2.text, let f3t = f3.text, let f4t = f4.text, let f5t = f5.text, let f6t = f6.text else {
90− presentAlertInvalidData(with: "Some fields are missing");
91− return
92− }
93−
94− if f1t.isEmpty || f2t.isEmpty || f3t.isEmpty || f4t.isEmpty || f5t.isEmpty || f6t.isEmpty {
95− presentAlertInvalidData(with: "Some fields are missing");
96− return
97− }
98−
99− let code = "\(f1.text!)\(f2.text!)\(f3.text!)\(f4.text!)\(f5.text!)\(f6.text!)"
100− if let codeToInt = Int(code)
101− {
102− loading.startAnimating()
103− Model.verify(with: codeToInt) { [weak self] in
104− // if everything is okay we can authemticicate
105− if !$0 {
106− self?.presentAlertInvalidData(with: "Wrong code. Try again!")
107− self?.loading.stopAnimating()
108− return
109− } else {
110− // Model.authemticiateMe
111− Model.authenticateMe { [weak self] (res) in
112− if res {
113− self?.onSuccessLogIn?()
114− }
115− }
116− return
117− }
118− }
119− }
120− }
121−
122− func setUpConstraint()
123− {
124− self.view.addSubview(loading)
125− loading.centerInSuperview()
126− // for keyboard notifications
127− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
128−
129− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
130− }
131−
132− @objc func handleKeyboardNotifications(notification: NSNotification){
133− if let userInfo = notification.userInfo {
134− // UIKeyboardFrameEndUserInfoKey
135− let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
136− bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? keyBoardFrame.height - self.view.safeAreaInsets.bottom : 0
137−
138− UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
139− self.view.layoutIfNeeded()
140− })
141− }
142− }
143−
144−}
GDproject/Controller/Log In/FacultyTableViewController.swiftdeleted−88
@@ -1,88 +0,0 @@
1−//
2−// FacultyTableViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−protocol ChosenFactulty: class {
12− func onChooseFaculty(faculty: Model.Faculty)
13−}
14−
15−class FacultyTableViewController: UITableViewController {
16−
17− weak var delegate: ChosenFactulty?
18−
19− var currentFaculties: [Model.Faculty] = []{
20− didSet {
21− tableView.reloadData()
22− }
23− }
24−
25− var isFiltering: Bool {
26− return searchController.isActive && !searchBarIsEmpty()
27− }
28−
29− func searchBarIsEmpty() -> Bool {
30− return searchController.searchBar.text?.isEmpty ?? true
31− }
32−
33− var searchController = UISearchController(searchResultsController: nil)
34−
35− override func viewDidLoad() {
36− super.viewDidLoad()
37−
38− self.navigationItem.title = "Faculties"
39− self.navigationItem.searchController = searchController
40− self.navigationItem.hidesSearchBarWhenScrolling = false
41− searchController.obscuresBackgroundDuringPresentation = false
42−
43− setUpTimer()
44− }
45−
46− func setUpTimer(){
47− Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { (timer) in
48− DispatchQueue.main.async { [weak self] in
49−
50− if self!.isFiltering {
51− Model.searchFaculty(string: (self?.searchController.searchBar.text)!) { [weak self] in
52− self?.currentFaculties = $0
53− }
54− }
55− }
56− }
57− }
58−
59−
60− // MARK: - Table view data source
61−
62− override func numberOfSections(in tableView: UITableView) -> Int {
63− return 1
64− }
65−
66− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
67− return currentFaculties.count
68− }
69−
70−
71− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
72− {
73− let cell = tableView.dequeueReusableCell(withIdentifier: "F", for: indexPath)
74−
75− cell.textLabel?.text = currentFaculties[indexPath.row].name
76− cell.detailTextLabel?.text = currentFaculties[indexPath.row].campusName
77− cell.selectionStyle = .none
78−
79− return cell
80− }
81−
82− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
83− delegate?.onChooseFaculty(faculty: currentFaculties[indexPath.row])
84− searchController.dismiss(animated: true, completion: nil)
85− self.navigationController?.popViewController(animated: true)
86− }
87−
88−}
GDproject/Controller/Log In/InititalsViewCell.swiftdeleted−23
@@ -1,23 +0,0 @@
1−//
2−// InititalsViewCell.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class InititalsViewCell: UITableViewCell {
12−
13− @IBOutlet weak var initialsTextField: UITextField!
14−
15− override func awakeFromNib() {
16− super.awakeFromNib()
17− // Initialization code
18− }
19−
20− func fill(with name: String){
21− initialsTextField.text = name
22− }
23−}
GDproject/Controller/Log In/LogInViewController.swiftdeleted−155
@@ -1,155 +0,0 @@
1−//
2−// LogInViewController.swift
3−// RxSwift
4−//
5−// Created by cstore on 01/03/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−import ReactiveSwift
12−import ReactiveCocoa
13−import Result
14−
15−class LogInViewController: UIViewController {
16−
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− }
35−
36− let logInLabel: UILabel = {
37− let label = UILabel()
38− label.text = "Log In"
39− label.textColor = .black
40− label.font = UIFont.boldSystemFont(ofSize: 34)
41− return label
42− }()
43−
44− let mailTextField: UITextField = {
45− let textField = UITextField()
46− textField.backgroundColor = #colorLiteral(red: 0.937254902, green: 0.937254902, blue: 0.9568627451, alpha: 1)
47− textField.placeholder = "Mail"
48− textField.borderStyle = .roundedRect
49− textField.textColor = .black
50− textField.autocorrectionType = UITextAutocorrectionType.no
51− textField.autocapitalizationType = UITextAutocapitalizationType.none
52− textField.clearButtonMode = .always
53− return textField
54− }()
55−
56− let logInButton: UIButton = {
57− let button = UIButton(type: .system)
58− button.setTitle("Log In", for: .normal)
59− button.setTitleColor(blueSystemColor, for: .normal)
60− button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
61− button.addTarget(self, action: #selector(handleTap), for: .touchUpInside)
62− button.isEnabled = false
63− return button
64− }()
65−
66− @objc func handleTap(){
67− loading.startAnimating()
68− authenticate?(mailTextField.text!)
69− }
70−
71− private lazy var keyboardBar = UIView()
72− private lazy var contentView = UIView()
73− private var bottomConstraint: NSLayoutConstraint?
74−
75− func setUpView(){
76− // logIn stack with textField and label
77− view.addSubview(contentView)
78− view.addSubview(loading)
79−
80− loading.centerInSuperview()
81−
82− contentView.edgesToSuperview(excluding: .bottom, insets: .left(16) + .right(16) + .top(80), usingSafeArea: true)
83− let views = [logInLabel, mailTextField]
84− contentView.stack(views, axis: .vertical, spacing: 10)
85− }
86−
87− func configureKeyboard(){
88−
89− mailTextField.keyboardType = .emailAddress
90− // configure keyboardBar setUp
91− view.addSubview(keyboardBar)
92− keyboardBar.height(50)
93− keyboardBar.edgesToSuperview(excluding: [.top,.bottom])
94− bottomConstraint = NSLayoutConstraint(item: keyboardBar, attribute: .bottom, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
95− view.addConstraint(bottomConstraint!)
96−
97− // configure keyboardBar components
98− keyboardBar.addSubview(logInButton)
99− logInButton.height(50)
100− logInButton.rightToSuperview(view.rightAnchor, offset: -16, relation: .equal, isActive: true)
101−
102− }
103−
104− func logicOfLogInInputValidation() -> ((String?)->()) {
105−
106− let logic: ((String?)->()) = { [weak self] (someText) in
107− if let text = someText, !text.isEmpty, text.contains("@") {
108− self?.logInButton.isEnabled = true
109− } else {
110− self?.logInButton.isEnabled = false
111− }
112− }
113−
114− return logic
115− }
116−
117− override func viewDidLoad() {
118− super.viewDidLoad()
119− self.view.backgroundColor = .white
120− setUpView()
121− configureKeyboard()
122−
123− let mailFieldValuesSignal: Signal<String, NoError> = mailTextField.reactive.continuousTextValues
124−
125− mailFieldValuesSignal.observeValues(logicOfLogInInputValidation())
126−
127− // for keyboard notifications
128− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
129−
130− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
131− }
132−
133−
134− @objc func handleKeyboardNotifications(notification: NSNotification){
135− if let userInfo = notification.userInfo{
136− // UIKeyboardFrameEndUserInfoKey
137− let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
138− bottomConstraint?.constant = notification.name == UIResponder.keyboardWillShowNotification ? -keyBoardFrame.height+view.safeAreaInsets.bottom : 0
139−
140− UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
141− self.view.layoutIfNeeded()
142− })
143− }
144− }
145−
146−}
147−
148−extension UIButton {
149− override open var isEnabled: Bool {
150− didSet {
151− let color = isEnabled ? self.titleLabel?.textColor.withAlphaComponent(1) : self.titleLabel?.textColor.withAlphaComponent(0.5)
152− self.setTitleColor(color, for: .normal)
153− }
154− }
155−}
GDproject/Controller/Log In/RegisterTableViewController.swiftdeleted−198
@@ -1,198 +0,0 @@
1−//
2−// RegisterTableViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class RegisterTableViewController: UITableViewController, ChosenFactulty
12−{
13−
14− func presentAlertInvalidData(message: String)
15− {
16− let alert = UIAlertController(title: "Invalid data", message: message, preferredStyle: .alert)
17− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
18− self.present(alert, animated: true, completion: nil)
19− }
20−
21− func onChooseFaculty(faculty: Model.Faculty) {
22− self.faculty = faculty
23− tableView.reloadData()
24− }
25−
26− weak var delegate: UpdateUser?
27−
28− var onRegistration: (()->())?
29−
30− var faculty: Model.Faculty?
31− var user: Model.NewRegistration = Model.NewRegistration(email: DataStorage.standard.getEmail()!, firstName: nil, middleName: nil, lastName: nil, faculty: nil)
32−
33− var userActive: Model.Users? {
34− didSet {
35− if let userA = userActive {
36− user.firstName = userA.firstName
37− user.middleName = userA.middleName
38− user.lastName = userA.lastName
39−
40− faculty = userA.faculty
41− self.updateUserIfCan = true
42− tableView.reloadData()
43− }
44− }
45− }
46−
47− var updateUserIfCan: Bool = false
48−
49− override func viewDidLoad()
50− {
51− super.viewDidLoad()
52−
53− navigationItem.largeTitleDisplayMode = .never
54− tableView.keyboardDismissMode = .interactive
55− navigationItem.title = user.email
56− navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(endRegistration))
57− }
58−
59−
60− @objc func endRegistration()
61− {
62− let fieldsMissing = "Some fields are missing. Add more information"
63− updateUser()
64− guard let faculty = faculty else { presentAlertInvalidData(message: fieldsMissing); return }
65−
66− user.faculty = faculty.url
67−
68− guard let name = user.firstName else { presentAlertInvalidData(message: fieldsMissing); return }
69− guard let middle = user.middleName else { presentAlertInvalidData(message: fieldsMissing); return }
70− guard let last = user.lastName else { presentAlertInvalidData(message: fieldsMissing); return }
71−
72− if updateUserIfCan {
73− guard let delegate = delegate else { return }
74− guard var userA = userActive else { return }
75−
76− // updating current
77− userA.firstName = name
78− userA.faculty = faculty
79− userA.middleName = middle
80− userA.lastName = last
81−
82− Model.userUpdate(with: user) { [weak self] in
83−
84− if $0 {
85− delegate.updateUserObj(with: userA)
86− self?.navigationController?.popViewController(animated: true)
87− } else {
88− self?.presentAlertInvalidData(message: "Something went wrong! Try again")
89− }
90−
91− }
92− } else {
93−
94− Model.register(object: user)
95− { [weak self] in
96− self?.onRegistration?()
97− }
98− }
99− }
100− // MARK: - Table view data source
101−
102− override func numberOfSections(in tableView: UITableView) -> Int {
103− return 2
104− }
105−
106− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
107−
108− switch section {
109− case 0:
110− return 3
111− default:
112− if let _ = faculty {
113− return 2
114− } else {
115− return 1
116− }
117− }
118− }
119−
120− override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
121− {
122− switch section {
123− case 0:
124− return "Initials"
125− default:
126− return "Faculty"
127− }
128− }
129−
130−
131− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
132− {
133− switch indexPath.section {
134− case 0:
135− let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! InititalsViewCell
136− switch indexPath.row{
137− case 0:
138− if let name = user.firstName {
139− cell.fill(with: name)
140− } else {
141− cell.initialsTextField.placeholder = "First name"
142− }
143− case 1:
144− if let name = user.middleName {
145− cell.fill(with: name)
146− } else {
147− cell.initialsTextField.placeholder = "Middle name"
148− }
149− default:
150− if let name = user.lastName {
151− cell.fill(with: name)
152− } else {
153− cell.initialsTextField.placeholder = "Last name"
154− }
155− }
156− cell.selectionStyle = .none
157− return cell
158− default:
159− switch indexPath.row {
160− case 0:
161− let cell = tableView.dequeueReusableCell(withIdentifier: "cell111", for: indexPath)
162− cell.selectionStyle = .none
163− return cell
164− default:
165− let cell = tableView.dequeueReusableCell(withIdentifier: "facultyCell", for: indexPath)
166− cell.textLabel?.text = faculty!.name
167− cell.detailTextLabel?.text = faculty!.campusName
168− cell.selectionStyle = .none
169− return cell
170− }
171− }
172− }
173−
174−
175− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
176− if indexPath.section == 1 && indexPath.row == 0 {
177−
178− updateUser()
179−
180− let vc = storyboard?.instantiateViewController(withIdentifier: "FacultyTableViewController") as! FacultyTableViewController
181−
182− vc.delegate = self
183−
184− self.navigationController?.pushViewController(vc, animated: true)
185− }
186− }
187−
188− func updateUser(){
189− guard let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as? InititalsViewCell else {return}
190− guard let cell1 = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? InititalsViewCell else {return}
191− guard let cell2 = tableView.cellForRow(at: IndexPath(row: 2, section: 0)) as? InititalsViewCell else {return}
192−
193− user.firstName = cell.initialsTextField.text!
194− user.middleName = cell1.initialsTextField.text!
195− user.lastName = cell2.initialsTextField.text!
196− }
197−
198−}
GDproject/Controller/LogInViewController.swiftnew file+138
@@ -0,0 +1,138 @@
1+//
2+// LogInViewController.swift
3+// NewsFeed
4+//
5+// Created by cstore on 20/01/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class LogInViewController: UIViewController {
12+
13+ @IBOutlet weak var mailTextField: UITextField!
14+
15+ static let titleColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)
16+
17+ var bottomConstraint: NSLayoutConstraint?
18+
19+ let logInButton: UIButton = {
20+ let button = UIButton(type: .system)
21+ button.setTitle("Log In", for: .normal)
22+ button.setTitleColor(titleColor, for: .normal)
23+ button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
24+ button.isEnabled = false
25+ button.addTarget(self, action: #selector(activateLogInProcess), for: .touchUpInside)
26+ return button
27+ }()
28+
29+ let keyboardBar: UIView = {
30+ let view = UIView()
31+ view.backgroundColor = .white
32+ return view
33+ }()
34+
35+ override func viewDidLoad() {
36+ super.viewDidLoad()
37+ setUpView()
38+ configureTapgesture()
39+ }
40+
41+ override func viewWillAppear(_ animated: Bool) {
42+ super.viewWillAppear(animated)
43+ // MARK:- uncomment when mail registration will be availiable
44+ //self.navigationController?.setNavigationBarHidden(true, animated: animated)
45+ }
46+
47+ override func viewWillDisappear(_ animated: Bool) {
48+ super.viewWillDisappear(animated)
49+ // MARK:- uncomment when mail registration will be availiable
50+ //self.navigationController?.setNavigationBarHidden(false, animated: animated)
51+ }
52+
53+ private func configureTapgesture(){
54+ let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
55+ view.addGestureRecognizer(tapGesture)
56+ }
57+
58+ @objc func handleTap(){
59+ view.endEditing(true)
60+ }
61+
62+ @objc func activateLogInProcess(){
63+ if logInButton.isEnabled {
64+ // MARK:- when log in is succeeded do I need to go there?
65+ let vc = storyboard!.instantiateViewController(withIdentifier: newsController) as! NewsController
66+ present(vc, animated: true) {
67+ print("logged in")
68+ }
69+ DataStorage.standard.setIsLoggedIn(value: true)
70+ view.endEditing(true)
71+ }
72+ }
73+
74+ func setUpView(){
75+ mailTextField.delegate = self
76+ view.addSubview(keyboardBar)
77+
78+ view.addConstraintsWithFormat(format: "H:|[v0]|", views: keyboardBar)
79+ view.addConstraintsWithFormat(format: "V:[v0(50)]", views: keyboardBar)
80+
81+ setUpBarComponents()
82+
83+ bottomConstraint = NSLayoutConstraint(item: keyboardBar, attribute: .bottom, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
84+ view.addConstraint(bottomConstraint!)
85+
86+ // for keyboard notifications
87+ NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
88+
89+ NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
90+
91+ // for log in button notifications
92+ NotificationCenter.default.addObserver(self, selector: #selector(inputDidChanged), name: UITextField.textDidChangeNotification, object: mailTextField)
93+
94+ NotificationCenter.default.addObserver(self, selector: #selector(inputDidChanged), name: UITextField.textDidBeginEditingNotification, object: mailTextField)
95+ }
96+
97+ @objc func inputDidChanged(notification: NSNotification){
98+ if mailTextField.text?.isEmpty ?? true
99+ {
100+ logInButton.isEnabled = false
101+ logInButton.setTitleColor(LogInViewController.titleColor.withAlphaComponent(0.5), for: .normal)
102+ }
103+ else
104+ {
105+ logInButton.isEnabled = true
106+ logInButton.setTitleColor(LogInViewController.titleColor.withAlphaComponent(1), for: .normal)
107+ }
108+ }
109+
110+ @objc func handleKeyboardNotifications(notification: NSNotification){
111+ if let userInfo = notification.userInfo{
112+ // UIKeyboardFrameEndUserInfoKey
113+ let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
114+ bottomConstraint?.constant = notification.name == UIResponder.keyboardWillShowNotification ? -keyBoardFrame.height+view.safeAreaInsets.bottom : 0
115+
116+ UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
117+ self.view.layoutIfNeeded()
118+ }) { (completed) in
119+
120+ }
121+ }
122+ }
123+
124+ func setUpBarComponents(){
125+ keyboardBar.addSubview(logInButton)
126+ keyboardBar.addConstraintsWithFormat(format: "H:[v0(60)]-16-|", views: logInButton)
127+ keyboardBar.addConstraintsWithFormat(format: "V:|[v0]|", views: logInButton)
128+ }
129+}
130+
131+
132+extension LogInViewController: UITextFieldDelegate{
133+ func textFieldShouldReturn(_ textField: UITextField) -> Bool
134+ {
135+ textField.resignFirstResponder()
136+ return true
137+ }
138+}
GDproject/Controller/Messages/ChatInfoViewController.swiftdeleted−308
@@ -1,308 +0,0 @@
1−//
2−// ChatInfoViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 02/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−/// Class for displaying chat info
12−///
13−class ChatInfoViewController: UITableViewController {
14−
15− enum PersonStatus{
16− case admin
17− case ordinary
18− }
19−
20− weak var delegate: UpdatableGroup?
21−
22− var groupChat: Model.Group? {
23− didSet{
24− if let groupChat = groupChat {
25− usersArray = groupChat.users.map { $0.key }
26− }
27− }
28− }
29−
30− var usersArray: [Int] = [] {
31− didSet {
32− tableView.reloadData()
33− }
34− }
35−
36− var users: [Int: Model.Users] = [:]
37−
38− func canIEditThisChat() -> PersonStatus
39− {
40− let myId = UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
41−
42− if let groupChatUserPermission = groupChat?.users[myId]?.isAdmin {
43− return groupChatUserPermission ? .admin : .ordinary
44− }
45−
46− return .ordinary
47− }
48−
49− var myPermissions: PersonStatus = .ordinary
50−
51−
52−
53− override func viewDidLoad() {
54− super.viewDidLoad()
55−
56− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
57− myPermissions = canIEditThisChat()
58− tableView.reloadData()
59−
60− switch myPermissions {
61− case .admin:
62− navigationItem.rightBarButtonItem = self.editButtonItem
63− default:
64− return
65− }
66− }
67−
68− // MARK: - Table view data source
69−
70− override func numberOfSections(in tableView: UITableView) -> Int {
71− return 3
72− }
73−
74− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
75− switch section {
76− case 0:
77− return 1
78− case 1:
79− return 1
80− default:
81− return usersArray.count + (myPermissions == .ordinary ? 0 : 1)
82− }
83− }
84−
85−
86− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
87− {
88− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
89−
90− if indexPath.row == 0 {
91− switch indexPath.section {
92− case 0:
93− cell.textLabel?.text = groupChat!.name
94− cell.selectionStyle = .none
95− return cell
96− case 1:
97− cell.textLabel?.text = "Leave chat"
98− cell.textLabel?.textColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
99− cell.selectionStyle = .none
100− return cell
101− default:
102− switch myPermissions{
103− case .admin:
104− cell.textLabel?.text = "Add participants"
105− cell.accessoryType = .disclosureIndicator
106− case .ordinary:
107− cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
108− }
109− cell.selectionStyle = .none
110− return cell
111− }
112− }
113−
114− switch myPermissions{
115− case .admin:
116− cell.textLabel?.text = name(for: users[usersArray[indexPath.row-1]])
117− case .ordinary:
118− cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
119− }
120− cell.selectionStyle = .none
121− return cell
122− }
123−
124− private func name(for user: Model.Users?) -> String {
125− if let user = user, let perm = groupChat?.users[user.id]?.isAdmin {
126− if perm {
127− return "🤴🏻 \(user.fullName())"
128− }
129− return "👤 \(user.fullName())"
130− }
131−
132− return "left"
133− }
134−
135− override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
136− {
137− switch section {
138− case 0:
139− return "Title"
140− case 1:
141− return "Opportunities"
142− default:
143− return "Participants"
144− }
145− }
146−
147−
148− func editName(for cell: UITableViewCell){
149− let alert = UIAlertController(title: "Are you sure?", message: "Title:", preferredStyle: .alert)
150−
151− let action1 = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
152−
153− alert.addTextField { [weak self] (tf) in
154− tf.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
155− tf.text = self?.groupChat?.name
156− }
157−
158− let action2 = UIAlertAction(title: "OK", style: .default) { [unowned self] _ in
159− let name = alert.textFields?.first?.text
160− cell.textLabel?.text = name
161− self.groupChat?.name = name!
162− Model.updateGroupChat(with: self.groupChat!)
163− self.delegate?.updateGroup(with: self.groupChat!)
164− }
165−
166− alert.addAction(action1)
167− alert.addAction(action2)
168−
169− present(alert, animated: true, completion: nil)
170− }
171− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
172− {
173− guard let groupChat = groupChat else {
174− return
175− }
176−
177− guard let cell = tableView.cellForRow(at: indexPath) else {
178− return
179− }
180−
181− if indexPath.row == 0 {
182− switch indexPath.section{
183− case 0:
184− switch myPermissions{
185− case .admin:
186− editName(for: cell)
187− default:
188− break
189− }
190− case 1:
191− Model.leaveGroupChat(id: groupChat.id) {
192− [weak self] in
193− self?.navigationController?.popViewController(animated: true)
194− }
195− default:
196− switch myPermissions{
197− case .admin:
198− showUserChoiceVC()
199− default:
200− showParticipantPage(with: usersArray[indexPath.row])
201− }
202− }
203− }
204−
205−
206− if indexPath.section == 2 && indexPath.row != 0 {
207− switch myPermissions{
208− case .admin:
209− showParticipantPage(with: usersArray[indexPath.row-1])
210− default:
211− showParticipantPage(with: usersArray[indexPath.row])
212− }
213− }
214− }
215−
216− var onUserDiplay: ((Int)->())?
217−
218− func showParticipantPage(with user: Int?) {
219− if let user = user {
220− onUserDiplay?(user)
221− }
222− }
223−
224− func showUserChoiceVC()
225− {
226− let vc = storyboard?.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
227−
228− vc.whatToDoWithSelection = { [weak self, weak vc] mapa in
229−
230− mapa.forEach { self?.users[$0.key] = Model.Channels.fullPeopleDict[$0.key] }
231− mapa.forEach { self?.groupChat?.users[$0.key] = $0.value }
232− vc?.navigationController?.popViewController(animated: true)
233− }
234−
235− navigationController?.pushViewController(vc, animated: true)
236− }
237−
238− override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
239− {
240− if editingStyle == UITableViewCell.EditingStyle.delete {
241− groupChat?.users[usersArray[indexPath.row-1]] = nil
242− }
243−
244− tableView.reloadData()
245− }
246−
247− override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
248− if indexPath.row == 0 {
249− return false
250− }
251−
252− return true
253− }
254−
255− override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
256− {
257− let editButton = UITableViewRowAction(style: .normal, title: "Promote") { [unowned self] (rowAction, indexPath) in
258−
259− self.tableView.beginUpdates()
260− self.groupChat?.users[self.usersArray[indexPath.row-1]]?.isAdmin = true
261− self.tableView.reloadRows(at: [indexPath], with: .none)
262− self.tableView.endUpdates()
263− }
264−
265− editButton.backgroundColor = #colorLiteral(red: 0.476841867, green: 0.5048075914, blue: 1, alpha: 1)
266−
267− let restrictButton = UITableViewRowAction(style: .normal, title: "Restrict") { [unowned self] (rowAction, indexPath) in
268−
269− self.tableView.beginUpdates()
270− self.groupChat?.users[self.usersArray[indexPath.row-1]]?.isAdmin = false
271− self.tableView.reloadRows(at: [indexPath], with: .none)
272− self.tableView.endUpdates()
273− }
274−
275− restrictButton.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
276−
277− let deleteButton = UITableViewRowAction(style: .normal, title: "Delete") { [unowned self] (action, indexPath) in
278−
279− self.tableView.beginUpdates()
280− self.groupChat?.users[self.usersArray[indexPath.row-1]] = nil
281− self.tableView.deleteRows(at: [indexPath], with: .none)
282− self.tableView.endUpdates()
283− }
284−
285− deleteButton.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
286−
287− return [editButton, restrictButton, deleteButton]
288− }
289−
290− /// update chatInfo
291− override func viewWillDisappear(_ animated: Bool) {
292−
293− defer {
294− super.viewWillDisappear(animated)
295− }
296−
297− guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else {
298− switch myPermissions {
299− case .ordinary:
300− return
301− case .admin:
302− Model.updateGroupChat(with: groupChat!)
303− delegate?.updateGroup(with: groupChat!)
304− }
305− return
306− }
307− }
308−}
GDproject/Controller/Messages/Dialog/DialogCell.swiftdeleted−132
@@ -1,132 +0,0 @@
1−//
2−// DialogCell.swift
3−// GDproject
4−//
5−// Created by cstore on 05/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−import MarkdownKit
12−
13−class DialogCell: UITableViewCell {
14−
15− let nameLabel: UIButton = {
16− let button = UIButton()
17− button.setTitleColor(.black, for: .normal)
18− button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
19− button.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left
20− return button
21− }()
22−
23− @objc func displayProfile()
24− {
25− if let id = self.user?.id {
26− print("diplay")
27− onUserDisplay?(id)
28− }
29− }
30−
31− var onUserDisplay: ((Int)->())?
32−
33−
34− let timeLabel: UILabel = {
35− let label = UILabel()
36− label.font = UIFont.systemFont(ofSize: 9)
37− label.textAlignment = NSTextAlignment.right
38− label.textColor = #colorLiteral(red: 0.4352941176, green: 0.4431372549, blue: 0.4745098039, alpha: 1)
39− return label
40− }()
41−
42− func createTextView(with text: NSAttributedString, _ isSelectable: Bool) -> UITextView
43− {
44− let textView = UITextView()
45− textView.isScrollEnabled = false
46− textView.isEditable = false
47− textView.sizeToFit()
48−
49− if isSelectable {
50− textView.isSelectable = true
51− } else {
52− textView.isUserInteractionEnabled = false
53− }
54−
55− textView.attributedText = text
56− return textView
57− }
58−
59− override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
60− {
61− super.init(style: style, reuseIdentifier: reuseIdentifier)
62− }
63−
64− required init?(coder aDecoder: NSCoder)
65− {
66− fatalError("init(coder:) has not been implemented")
67− }
68−
69− var user: Model.Users? {
70− didSet{
71− nameLabel.setTitle(user!.fullName(), for: .normal)
72− }
73− }
74−
75− var textView: UITextView!
76−
77− func fill(with markdownText: NSAttributedString, byUser: Model.Users, when: String)
78− {
79− let myId = DataStorage.standard.getUserId()
80− // important
81− contentView.subviews.forEach({ $0.removeFromSuperview() })
82−
83− nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
84−
85− self.user = byUser
86− textView = createTextView(with: markdownText, true)
87− textView.layer.cornerRadius = 10
88− textView.clipsToBounds = true
89−
90− self.contentView.addSubview(textView)
91− self.contentView.addSubview(timeLabel)
92−
93− timeLabel.text = when.getDate()
94− textView.width(min: 50, max: self.contentView.bounds.width-70, priority: .required, isActive: true)
95−
96− if myId == byUser.id
97− {
98− layoutMyMessage()
99− } else {
100− layOutOtherMessage()
101− }
102− }
103−
104− func layOutOtherMessage(){
105− self.contentView.addSubview(nameLabel)
106−
107− nameLabel.setTitle(user!.fullName(), for: .normal)
108−
109− nameLabel.edgesToSuperview(excluding: .bottom, insets: .top(4) + .left(8))
110− textView.edgesToSuperview(excluding: [.top, .right] , insets: .left(8) + .bottom(20))
111− textView.topToBottom(of: nameLabel)
112−
113− textView.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
114− textView.textColor = .white
115− timeLabel.edgesToSuperview(excluding: .top, insets: .right(70) + .left(8))
116− timeLabel.topToBottom(of: textView, offset: 4)
117− timeLabel.textAlignment = .left
118− }
119−
120− func layoutMyMessage()
121− {
122− textView.edgesToSuperview(excluding: .left, insets: .right(8) + .bottom(20) + .top(4))
123− textView.backgroundColor = UIColor(red:0.08, green:0.49, blue:0.98, alpha:1.0)
124− textView.textColor = .white
125− timeLabel.edgesToSuperview(excluding: .top, insets: .left(70) + .right(8))
126− timeLabel.topToBottom(of: textView, offset: 4)
127− timeLabel.textAlignment = .right
128− }
129−}
130−
131−
132−
GDproject/Controller/Messages/Dialog/DialogViewController.swiftdeleted−340
@@ -1,340 +0,0 @@
1−//
2−// DialogViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 01/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−import Marklight
12−
13−protocol UpdatableGroup:class {
14− func updateGroup(with group: Model.Group)
15−}
16−
17−class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegate, UITableViewDataSource
18−{
19− var onUserDisplay: ((Int)->())?
20−
21− var tableView: UITableView = UITableView()
22−
23− func updateGroup(with group: Model.Group){
24− self.groupChat?.group = group
25− setTitleForGroup(groupChat: groupChat!)
26− }
27−
28− let cellId = "cell3"
29− var onInfoShow: (()->())?
30−
31− var dialog: Model.Dialog? {
32− didSet{
33− switch dialog! {
34− case .groupChat(let chat):
35− self.groupChat = chat
36− case .userChat(let chat):
37− self.userChat = chat
38− }
39− }
40− }
41−
42− var groupChat: Model.GroupChat?
43− var userChat: Model.UserChat?
44−
45− var users: [Int: Model.Users]?
46−
47− var groupId: Int?
48−
49− var cellData: [PostCellData] = [] {
50− didSet {
51− tableView.reloadData()
52− canBePaginated = true
53− }
54− }
55−
56− override func viewDidLoad() {
57− super.viewDidLoad()
58−
59− setConstraints()
60− magicForKeyboardChanges()
61−
62− self.tableView.delegate = self
63− self.tableView.dataSource = self
64−
65− tableView.setContentOffset(CGPoint(x: 0, y: 50), animated: false)
66−
67− navigationItem.largeTitleDisplayMode = .never
68−
69− tableView.keyboardDismissMode = .onDrag
70− tableView.separatorStyle = .none
71− tableView.register(DialogCell.self, forCellReuseIdentifier: cellId)
72− tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
73− tableView.contentInsetAdjustmentBehavior = .never
74− tableView.contentOffset = CGPoint(x: 0, y: 30)
75−
76− if let groupChat = groupChat {
77− setTitleForGroup(groupChat: groupChat)
78− } else if let userChat = userChat{
79− setTitleForChat(userChat: userChat)
80− }
81− }
82−
83− var messageSendView: UIView = {
84− let view = UIView()
85− view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
86− return view
87− }()
88−
89− var messageTextView: UITextView =
90− {
91− let textStorage = MarklightTextStorage()
92− textStorage.marklightTextProcessor.codeColor = UIColor.orange
93− textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
94− textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
95− textStorage.marklightTextProcessor.codeFontName = "Courier"
96− textStorage.marklightTextProcessor.fontTextStyle = UIFont.TextStyle.subheadline.rawValue
97− textStorage.marklightTextProcessor.hideSyntax = false
98−
99− let layoutManager = NSLayoutManager()
100−
101− // Assign the `UITextView`'s `NSLayoutManager` to the `NSTextStorage` subclass
102− //textStorage.addLayoutManager(textView.layoutManager)
103− textStorage.addLayoutManager(layoutManager)
104−
105− let textContainer = NSTextContainer()
106− layoutManager.addTextContainer(textContainer)
107−
108− let textView = UITextView(frame: CGRect.zero, textContainer: textContainer)
109− textView.isEditable = true
110− textView.isScrollEnabled = true
111− textView.backgroundColor = .white
112− return textView
113− }()
114−
115− var sendButton: UIButton = {
116− let button = UIButton()
117− button.setTitle("Send", for: .normal)
118− button.setTitleColor(.blue, for: .normal)
119− button.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
120− button.addTarget(self, action: #selector(sendMessage), for: .touchUpInside)
121− return button
122− }()
123−
124− @objc func sendMessage()
125− {
126− var destination: Model.MessageDestination?
127−
128− if let group = groupChat {
129− destination = Model.MessageDestination.groupChatDestination(group.group.id)
130− } else if let user = userChat {
131− destination = Model.MessageDestination.userChatDestination(user.user)
132− }
133−
134− if let destination = destination
135− {
136− Model.sendMessage(message: Model.SendMessage(body: Model.Attachments(markdown: messageTextView.text), destination: destination)) { [unowned self] in
137−
138− switch $0 {
139− case .success, .success1:
140− self.getMessagesNew(for: self.dialog!)
141− self.messageTextView.text = ""
142− default:
143− self.showAlertOn(result: $0)
144− }
145− }
146−
147− prevLast = -1
148− }
149− }
150−
151− var lineView: UIView = {
152− let view = UIView()
153− view.backgroundColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
154− return view
155− }()
156−
157− var bottomConstraint: NSLayoutConstraint!
158−
159− func setConstraints(){
160− self.view.addSubview(tableView)
161− self.view.addSubview(messageSendView)
162−
163− messageSendView.addSubview(messageTextView)
164− messageSendView.addSubview(sendButton)
165− messageSendView.addSubview(lineView)
166−
167− messageSendView.edgesToSuperview(excluding: [.top,.bottom])
168−
169− bottomConstraint = NSLayoutConstraint(item: messageSendView, attribute: .bottom, relatedBy: .equal, toItem: self.view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
170− view.addConstraint(bottomConstraint)
171−
172− messageSendView.height(60)
173−
174− sendButton.edgesToSuperview(excluding: .left)
175− sendButton.width(60)
176−
177− lineView.edgesToSuperview(excluding: .bottom)
178− lineView.height(0.5)
179−
180− messageTextView.edgesToSuperview(excluding: .right)
181− messageTextView.rightToLeft(of: sendButton)
182−
183− tableView.edgesToSuperview(excluding: .bottom)
184− tableView.bottomToTop(of: messageSendView)
185−
186− self.view.layoutSubviews()
187− }
188−
189− func magicForKeyboardChanges()
190− {
191− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
192−
193− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
194− }
195−
196− @objc func handleKeyboardNotifications(notification: NSNotification){
197− if let userInfo = notification.userInfo{
198− // UIKeyboardFrameEndUserInfoKey
199−
200− let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
201−
202− bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? -(keyBoardFrame.height) + self.view.safeAreaInsets.bottom : 0
203−
204− UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
205− self.view.layoutIfNeeded()
206− }) { (completed) in
207−
208− }
209− }
210− }
211−
212− func setTitleForChat(userChat: Model.UserChat){
213− navigationItem.title = "\(users![userChat.user]!.fullName())"
214− navigationItem.rightBarButtonItem = UIBarButtonItem(title: "👤", style: .plain, target: self, action: #selector(showPersonPage))
215− }
216−
217− @objc func showPersonPage(){
218− if let id = userChat?.user{
219− onUserDisplay?(id)
220− }
221− }
222−
223− func setTitleForGroup(groupChat: Model.GroupChat){
224− navigationItem.title = "\(groupChat.group.name)"
225− navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Info", style: .plain, target: self, action: #selector(moveToInfoVC))
226− }
227−
228− // onInfoShow
229− @objc func moveToInfoVC(){
230− let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: chatInfoViewController) as! ChatInfoViewController
231−
232− vc.delegate = self
233− vc.users = users!
234− vc.onUserDiplay = onUserDisplay
235−
236− if let groupChat = groupChat {
237− vc.groupChat = groupChat.group
238− }
239−
240− navigationController?.pushViewController(vc, animated: true)
241− }
242−
243− var currentMessagesInChat: [Model.LastMessage] = [] {
244− didSet
245− {
246− cellData = currentMessagesInChat.map { PostCellData(attributedData: PostCellData.create(with: [$0.body])) }
247− }
248− }
249−
250− // MARK: - Table view data source
251−
252− func numberOfSections(in tableView: UITableView) -> Int {
253− return 1
254− }
255−
256− func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
257− return cellData.count
258− }
259−
260− override func viewWillAppear(_ animated: Bool)
261− {
262− super.viewWillAppear(animated)
263− tabBarController?.tabBar.isHidden = true
264−
265− if let dialog = dialog {
266− getMessagesNew(for: dialog)
267− }
268− }
269−
270− func getMessages(for dialog: Model.Dialog, starting from: Int? = nil)
271− {
272− switch dialog {
273− case .groupChat(let groupChat):
274− Model.getMessagesFor(typeOfChat: Model.Dialog.groupChat(groupChat), chat: groupChat.group.id, exclusiveFrom: from)
275− { [weak self] in
276− self?.currentMessagesInChat.append(contentsOf: $0)
277− }
278− case .userChat(let userChat):
279− Model.getMessagesFor(typeOfChat: Model.Dialog.userChat(userChat), chat: userChat.user, exclusiveFrom: from)
280− { [weak self] in
281− self?.currentMessagesInChat.append(contentsOf: $0)
282− }
283− }
284− }
285−
286−
287− func getMessagesNew(for dialog: Model.Dialog, starting from: Int? = nil)
288− {
289− switch dialog {
290− case .groupChat(let groupChat):
291− Model.getMessagesFor(typeOfChat: Model.Dialog.groupChat(groupChat), chat: groupChat.group.id, exclusiveFrom: from)
292− { [weak self] in
293− self?.currentMessagesInChat = $0
294− }
295− case .userChat(let userChat):
296− Model.getMessagesFor(typeOfChat: Model.Dialog.userChat(userChat), chat: userChat.user, exclusiveFrom: from)
297− { [weak self] in
298− self?.currentMessagesInChat = $0
299− }
300− }
301− }
302−
303− func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
304− {
305− let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! DialogCell
306−
307− //In cellForRowAtIndexPath
308− cell.transform = CGAffineTransform(scaleX: 1, y: -1)
309− cell.selectionStyle = .none
310−
311−
312− if let user = users?[currentMessagesInChat[indexPath.row].author]
313− {
314− cell.fill(with: cellData[indexPath.row].attributedData, byUser: user, when: currentMessagesInChat[indexPath.row].time)
315−
316− cell.onUserDisplay = onUserDisplay
317− }
318−
319− return cell
320− }
321−
322− var prevLast = -1
323− var canBePaginated = false
324− func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
325− {
326− if indexPath.row == cellData.count - 1 && prevLast != indexPath.row && canBePaginated && cellData.count >= 24
327− {
328− print("exclusiveFrom \(currentMessagesInChat.last?.id ?? 0)")
329− if let dialog = dialog
330− {
331− getMessages(for: dialog, starting: currentMessagesInChat.last?.id)
332− }
333−
334− prevLast = indexPath.row
335− }
336− }
337−}
338−
339−
340−
GDproject/Controller/Messages/MessageViewCell.swiftdeleted−38
@@ -1,38 +0,0 @@
1−//
2−// MessageViewCell.swift
3−// GDproject
4−//
5−// Created by cstore on 13/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class MessageViewCell: UITableViewCell {
12−
13− @IBOutlet weak var dialogName: UILabel!
14−
15− @IBOutlet weak var lastMessagePreview: UILabel!
16−
17− @IBOutlet weak var dateLabel: UILabel!
18−
19− override func awakeFromNib() {
20− super.awakeFromNib()
21− // Initialization code
22− }
23−
24− func fill(with dialog: Model.Dialog, user: Model.Users? = nil)
25− {
26− switch dialog {
27−
28− case .groupChat(let group):
29− dialogName.text = group.group.name
30− lastMessagePreview.text = group.lastMessage?.body.markdown
31− dateLabel.text = group.lastMessage?.time.getDate()
32− case .userChat(let userChat):
33− dialogName.text = "👤 \(user!.fullName())"
34− lastMessagePreview.text = userChat.lastMessage?.body.markdown
35− dateLabel.text = userChat.lastMessage?.time.getDate()
36− }
37− }
38−}
GDproject/Controller/Messages/MessagesViewController.swiftdeleted−181
@@ -1,181 +0,0 @@
1−//
2−// MessagesViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 01/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−protocol SelectableDialog: class {
12− func openDialog(with dialog: Model.Dialog)
13−}
14−
15−class MessagesViewController: UITableViewController, UISearchControllerDelegate, UISearchResultsUpdating, SelectableDialog {
16−
17− func openDialog(with dialog: Model.Dialog) {
18− onDialogDisplay?((dialog, users))
19− }
20−
21− func updateSearchResults(for searchController: UISearchController) {
22−
23− let filteredData = currentActiveDialogs
24− let inputText = searchController.searchBar.text ?? ""
25−
26− let filteredResults = filteredData.filter {
27−
28− switch $0 {
29− case .groupChat(let gropuChat):
30− return gropuChat.group.name.contains(inputText)
31−
32− case .userChat(let userChat):
33− let user = users[userChat.user]
34− guard let u = user else { return false }
35− return u.fullName().contains(inputText)
36−
37− }
38−
39− }
40−
41− // Apply the filtered results to the search results table.
42− if let resultsController = searchController.searchResultsController as? SuggestedDialogsTableViewController {
43− resultsController.users = users
44− resultsController.currentDialogs = filteredResults
45− resultsController.tableView.reloadData()
46− }
47− }
48−
49− // curreent Active which can be displayed
50− var currentActiveDialogs: [Model.Dialog] = [] {
51− didSet {
52− tableView.reloadData()
53− }
54− }
55−
56− func setUpSearchContr(){
57−
58− searchController?.delegate = self
59− searchController?.obscuresBackgroundDuringPresentation = true
60− navigationItem.searchController = searchController
61− definesPresentationContext = true
62− searchController?.searchResultsUpdater = self
63− searchController?.searchBar.placeholder = "Search dialogs"
64−
65− }
66−
67− // curreent users
68− var users: [Int: Model.Users] = [:]
69−
70− var onUserDisplayList: (()->())?
71−
72− var onDialogDisplay: (((dialog: Model.Dialog, users: [Int:Model.Users]))->())?
73−
74− var searchController: UISearchController?
75−
76− override func viewDidLoad() {
77− super.viewDidLoad()
78−
79− let updater = SuggestedDialogsTableViewController()
80−
81− updater.delegate = self
82− searchController = UISearchController(searchResultsController: updater)
83−
84− // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
85− self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Write", style: .plain, target: self, action: #selector(choosePerson))
86−
87− self.navigationItem.title = "Messages"
88− // self.navigationItem.largeTitleDisplayMode = .always
89− setUpSearchContr()
90− navigationController?.navigationBar.prefersLargeTitles = true
91− self.navigationItem.hidesSearchBarWhenScrolling = false
92− }
93−
94− @objc func choosePerson(){
95− onUserDisplayList?()
96− }
97−
98− override func viewWillAppear(_ animated: Bool) {
99− super.viewWillAppear(animated)
100− tabBarController?.tabBar.isHidden = false
101− Model.getChatAll { [weak self] in
102− self?.currentActiveDialogs = $0.0
103− self?.users = $0.1
104− }
105− }
106−
107− // MARK: - Table view data source
108− override func numberOfSections(in tableView: UITableView) -> Int {
109− return 1
110− }
111−
112− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
113− return currentActiveDialogs.count
114− }
115−
116−
117− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
118− {
119− let cell = tableView.dequeueReusableCell(withIdentifier: "MessageViewCell", for: indexPath) as! MessageViewCell
120−
121− switch currentActiveDialogs[indexPath.row].self {
122− case .groupChat:
123− cell.fill(with: currentActiveDialogs[indexPath.row])
124− case .userChat(let userChat):
125− cell.fill(with: currentActiveDialogs[indexPath.row], user: users[userChat.user])
126− }
127−
128− return cell
129− }
130−
131− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
132− let tuple = (currentActiveDialogs[indexPath.row],users)
133− onDialogDisplay?(tuple)
134− }
135−}
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.swiftdeleted−67
@@ -1,67 +0,0 @@
1−//
2−// PeopleToWriteViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 01/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class PeopleToWriteViewController: UITableViewController {
12−
13− // TODO: - edit button when it's used for selection
14− var whatToDoWithSelection: (([Int: Model.UserPermission])->())?
15−
16− let searchC = UISearchController(searchResultsController: nil)
17−
18− let users = Model.Channels.fullPeople
19−
20− var chosenUsers: [Int: Model.UserPermission] = [:]
21−
22− override func viewDidLoad() {
23− super.viewDidLoad()
24−
25− tableView.isEditing = true
26− self.navigationItem.title = "People"
27−
28− self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(newMessage))
29−
30− self.navigationItem.largeTitleDisplayMode = .never
31− self.navigationItem.searchController = searchC
32− self.navigationItem.hidesSearchBarWhenScrolling = false
33− }
34−
35− override func setEditing(_ editing: Bool, animated: Bool) {
36− super.setEditing(true, animated: animated)
37− }
38−
39− override func numberOfSections(in tableView: UITableView) -> Int {
40− return 1
41− }
42−
43− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
44− return users.count
45− }
46−
47− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
48− chosenUsers[users[indexPath.row].id] = Model.UserPermission(isAdmin: false)
49− }
50−
51− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
52− {
53− let cell = tableView.dequeueReusableCell(withIdentifier: "peopleToWriteCell", for: indexPath)
54−
55− cell.textLabel?.text = users[indexPath.row].fullName()
56−
57− return cell
58− }
59−
60− @objc func newMessage()
61− {
62− if chosenUsers.count != 0
63− {
64− whatToDoWithSelection?(chosenUsers)
65− }
66− }
67−}
GDproject/Controller/Profile/BasicInfoController.swift+12−16
@@ -16,20 +16,17 @@ struct CellData{
1616
1717class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
1818
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] = [ ]
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+ ]
3027
3128 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
32− if (dataSourse[section].opened) {
29+ if (dataSourse[section].opened){
3330 return dataSourse[section].sectionData.count + 1
3431 } else {
3532 return 1
@@ -42,15 +39,14 @@ class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDat
4239
4340 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
4441 if indexPath.row == 0 {
45− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
46− cell.textLabel?.text = dataSourse[indexPath.section].title
42+ let cell = tableView.dequeueReusableCell(withIdentifier: basicInfoCellId, for: indexPath) as! BasicInfoCell
43+ cell.fill(title: dataSourse[indexPath.section].title)
4744 cell.accessoryType = .disclosureIndicator
4845 cell.selectionStyle = .none
4946 return cell
5047 } else {
51− let cell = tableView.dequeueReusableCell(withIdentifier: infoCellId, for: indexPath) as! InfoCell
48+ let cell = tableView.dequeueReusableCell(withIdentifier: infoCellId, for: indexPath) as! InfoCell
5249 cell.fill(title: dataSourse[indexPath.section].sectionData[indexPath.row - 1])
53− cell.accessoryType = .none
5450 cell.selectionStyle = .none
5551 return cell
5652 }
GDproject/Controller/Profile/InfoCell.swift+1−2
@@ -16,9 +16,8 @@ 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
2221 label.textColor = .black
2322 return label
2423 }()
GDproject/Controller/Profile/ProfileViewController.swift+41−171
@@ -9,17 +9,8 @@
99import UIKit
1010import TinyConstraints
1111
12−protocol UpdateUser: class {
13− func updateUserObj(with user: Model.Users)
14−}
15−
16−class ProfileViewController: UIViewController, UpdateUser
12+class ProfileViewController: UIViewController
1713{
18− func updateUserObj(with user: Model.Users)
19− {
20− self.user = user
21− Model.Channels.fullPeopleDict[user.id] = user
22− }
2314
2415 @IBOutlet weak var segmentedControl: UISegmentedControl!
2516
@@ -39,211 +30,91 @@ class ProfileViewController: UIViewController, UpdateUser
3930
4031 @IBOutlet weak var newMessageButton: UIButton!
4132
42− var logOut: (()->())?
4333
44− var deleteAllSessions: (()->())?
45−
46− var onSettings: (()->())?
47−
48− @IBAction func sendMessage(_ sender: UIButton)
49− {
50− if let userId = idProfile
51− {
52− let createdDialog = Model.Dialog.userChat(Model.UserChat(user: userId))
53− let vc = DialogViewController()
54− vc.users = Model.Channels.fullPeopleDict
55− vc.dialog = createdDialog
56− self.navigationController?.pushViewController(vc, animated: true)
57− }
34+ func fill(with user: User){
35+ self.facultyLabel.text = user.faculty ?? ""
36+ self.nameLabel.text = "\(user.initials.name) \(user.initials.optional ?? "")"
37+ self.surnameLabel.text = user.initials.surname
38+ self.profileImageView.image = #imageLiteral(resourceName: "kitten").roundedImage
39+ self.placeLabel.text = user.placeOfWork
5840 }
5941
60− var protoDictionary: [String: UIImage] = ["135213": #imageLiteral(resourceName: "9"), "135288": #imageLiteral(resourceName: "5051"), "22723" : #imageLiteral(resourceName: "69"), "135083": #imageLiteral(resourceName: "42")]
42+ var user: User = User(surname: "Богомазова", name: "Вероника", optional: "Львовна", emailName: "vbogomazova", id: 2, place: "📍Москва, Кочновский пр. 3", faculty: "Методист: Факультет Компьютерных наук")
6143
62− func fill(with user: Model.Users)
63− {
64− self.facultyLabel.text = user.faculty.name
65− self.nameLabel.text = "\(user.firstName) \(user.middleName)"
66− self.surnameLabel.text = "\(user.lastName)"
67− self.profileImageView.image = protoDictionary[user.faculty.campusCode]?.roundedImage
68− self.placeLabel.text = "📍\(user.faculty.address)"
69− if user.id == DataStorage.standard.getUserId() {
70− newMessageButton.isHidden = true
71− } else {
72− newMessageButton.isHidden = false
73− }
74− }
75−
76− var user: Model.Users? {
77− didSet {
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− }
86− }
87− }
88−
89− var channel: Model.Channels? {
90− didSet {
91− self.update()
92− }
93− }
94−
95− func update()
96− {
97− Model.getAnonymousChannel(by: channel!) { [unowned self] in
98− self.posts.dataSourse = $0.posts
99− self.posts.dictionary = $0.users
100− self.user = $0.users[self.idProfile!]
101− }
102− }
103−
104− var basicInfo = BasicInfoController()
105− var posts = NewsVC()
44+ let basicInfo = BasicInfoController()
45+ let posts = NewsVC()
10646
10747 override func viewDidLoad()
10848 {
10949 super.viewDidLoad()
110− if idProfile == nil {
111− idProfile = DataStorage.standard.getUserId()
112− }
113−
50+
51+ posts.dataSourse = [Post(dataArray: [.text("Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. comme Aldus PageMaker. est qu'il possède une distribution de lettres plus ou moins normale, et en tout cas comparable avec celle du français standard. De nombreuses suites logicielles de mise en page ou éditeurs de sites Web ont fait du Lorem Ipsum leur faux texte par défaut, et une recherche pour 'Lorem Ipsum' vous conduira vers de nombreux sites qui n'en sont encore qu'à leur phase de construction. Plusieurs versions sont apparues avec le temps, parfois par accident, souvent intentionnellement (histoire d'y rajouter de petits clins d'oeil, voire des phrases embarassantes).")]), Post(dataArray: [.text("Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment, par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker. .")])]
52+
53+ // basicInfo.dataSourse =
54+
11455 posts.viewController = self
11556 posts.type = .NONE
116− posts.currChannel = channel
117−
118− posts.onFullPost = {
119− [weak self] (type,post) in
120−
121− let vc = self?.storyboard?.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
122− vc.type = type
123− vc.post = post
124− self?.navigationController!.pushViewController(vc, animated: true)
125− }
12657
12758 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
12859
12960 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
13061
13162 tableView.register(BasicInfoCell.self, forCellReuseIdentifier: basicInfoCellId)
132−
63+
13364 tableView.register(InfoCell.self, forCellReuseIdentifier: infoCellId)
13465
13566 posts.viewController = self
13667
68+ fill(with: user)
13769 tableView.delegate = posts
13870 tableView.dataSource = posts
13971 tableView.reloadData()
14072 }
14173
142− var idProfile: Int? {
143− didSet {
144− channel = Model.Channels(people: [idProfile!], name: "", id: 0, tags: [])
145− }
146− }
147−
14874 override func viewWillAppear(_ animated: Bool) {
149− tabBarController?.tabBar.isHidden = false
150−
151− if idProfile == nil {
152− idProfile = DataStorage.standard.getUserId()
153− }
154− user = Model.Channels.fullPeopleDict[idProfile!]
155−
156− update()
157−
15875 setUpNavigarionBar()
15976 }
16077
16178 func setUpNavigarionBar(){
162− // navigationController?.navigationBar.prefersLargeTitles = true
79+ navigationController?.navigationBar.prefersLargeTitles = true
80+ navigationItem.title = user.login
16381 let uibarbutton = UIBarButtonItem(title: "More", style: .plain, target: self, action: #selector(showInformation))
16482 navigationItem.rightBarButtonItems = [uibarbutton]
16583 navigationItem.largeTitleDisplayMode = .always
16684 }
16785
86+
87+ let copyLink: UIAlertAction = {
88+ let b = UIAlertAction(title: "Copy link", style: .default)
89+ return b
90+ }()
91+
16892 @objc func showInformation(){
16993
170− let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
171−
172−
173− let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
174−
94+ // drafts
95+ // saved
17596
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− }
97+ let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
98+ let editAction = UIAlertAction(title: "Edit profile", style: .default)
99+ let settingsAction = UIAlertAction(title: "Setting", style: .default)
100+ { [weak self] (_) in
236101
237− optionMenu.addAction(channelAction)
102+ let vc = self?.storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
103+ self?.navigationController?.pushViewController(vc, animated: true)
238104 }
239105
106+ let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
107+ let shareAction = UIAlertAction(title: "Share", style: .default)
108+
109+ optionMenu.addAction(editAction)
110+ optionMenu.addAction(settingsAction)
111+ optionMenu.addAction(copyLink)
112+ optionMenu.addAction(shareAction)
240113 optionMenu.addAction(cancelAction)
114+
241115 self.present(optionMenu, animated: true, completion: nil)
242116 }
243117
244− deinit {
245− print("profile clear")
246− }
247118
248119 @IBAction func valueChanged(_ sender: UISegmentedControl) {
249120 let index = sender.selectedSegmentIndex
@@ -267,7 +138,6 @@ class ProfileViewController: UIViewController, UpdateUser
267138 func changeToBasicInfo(){
268139 tableView.delegate = basicInfo
269140 tableView.dataSource = basicInfo
270− basicInfo.userInfo = self.user
271141 tableView.reloadData()
272142 }
273143}
GDproject/DataStorage.swift+8−23
@@ -7,7 +7,6 @@
77//
88
99import Foundation
10−import UIKit
1110
1211/**
1312 _DataStorage_ class is aimed to store user private settings
@@ -17,37 +16,25 @@ class DataStorage{
1716
1817 private init(){}
1918
20− //weak var coordinator: LogInCoordinator?
2119 static let standard = DataStorage()
2220
21+ // add channel
22+
23+ // delete channel
24+
2325 /**
2426 Function for setting log in status of user
2527 */
26− func setIsLoggedIn(value: Bool, with id: Int){
28+ func setIsLoggedIn(value: Bool){
2729 UserDefaults.standard.set(value, forKey: UserDefaultsKeys.loggedIn.rawValue)
28− setUserKey(with: id)
29− isLoggedIn = UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue)
30− }
31−
32− func setUserKey(with id: Int){
33− UserDefaults.standard.set(id, forKey: UserDefaultsKeys.id.rawValue)
34− }
35−
36− func getUserId() -> Int {
37− return UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
38− }
39−
40− func setEmail(email: String) {
41− UserDefaults.standard.set(email, forKey: UserDefaultsKeys.email.rawValue)
4230 }
4331
44− func getEmail() -> String? {
45− return UserDefaults.standard.string(forKey: UserDefaultsKeys.email.rawValue)
46− }
4732 /**
4833 Function to determine is user logged in already or not
4934 */
50− var isLoggedIn: Bool = UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue)
35+ func isLoggedIn() -> Bool {
36+ return UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue)
37+ }
5138}
5239
5340/**
@@ -55,6 +42,4 @@ class DataStorage{
5542 */
5643enum UserDefaultsKeys: String{
5744 case loggedIn
58− case id
59− case email
6045}
GDproject/Extentions.swift−73
@@ -34,76 +34,3 @@ extension UIView
3434 addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: viewsDictionary))
3535 }
3636}
37−
38−
39−extension UIStoryboard {
40−
41− private static let userEdit = UIStoryboard(name: "Main", bundle: nil)
42−
43− class func makeChannelsListController() -> ChannelListController {
44− return UIStoryboard.userEdit.instantiateViewController(withIdentifier: channelListControllerId) as! ChannelListController
45− }
46−
47− class func makeNewsController() -> NewsController {
48− return UIStoryboard.userEdit.instantiateViewController(withIdentifier: newsController) as! NewsController
49− }
50−
51− class func tabBarController() -> UITabBarController{
52− return UIStoryboard.userEdit.instantiateViewController(withIdentifier: "TabBar") as! UITabBarController
53− }
54−
55− class func navRoot() -> UINavigationController{
56− return UIStoryboard.userEdit.instantiateViewController(withIdentifier: "root") as! UINavigationController
57− }
58−
59− class func makeLogIn() -> LogInViewController {
60− return UIStoryboard.userEdit.instantiateViewController(withIdentifier: logInController) as! LogInViewController
61− }
62−}
63−
64−
65−extension String {
66− func getDate() -> String
67− {
68− let dateFormatter = DateFormatter()
69− dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"//this your string date format
70− dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
71− let date = dateFormatter.date(from: self)
72−
73− dateFormatter.dateFormat = "MMM d, yyyy HH:mm" ///this is what you want to convert format
74− dateFormatter.timeZone = NSTimeZone.local
75− let timeStamp = dateFormatter.string(from: date!)
76−
77− return timeStamp
78− }
79−}
80−
81−extension UIViewController {
82− func showAlertOn(result: ResultR) {
83−
84− let message: String
85−
86− switch result {
87− case .impossibleContent:
88− message = "Impossible content"
89− case .exceededContent:
90− message = "The content exceeded"
91− case .longContent:
92− message = "The content is too long"
93− case .badAccess:
94− message = "Try reloading the page again"
95− case .alreadyRegistered:
96− message = "User is already registered"
97− case .tooMuchToAdd:
98− message = "Limit of channels exceeded"
99− case .success, .success1:
100− return
101− default:
102− message = "Something went wrong"
103− }
104−
105− let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
106− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
107− self.present(alert, animated: true, completion: nil)
108− }
109−}
GDproject/Simple model/Channel.swift+3−10
@@ -8,23 +8,16 @@
88
99import Foundation
1010
11−class Channel: Equatable {
12− static func == (lhs: Channel, rhs: Channel) -> Bool {
13− return (lhs.title == rhs.title &&
14− lhs.subtitle == rhs.subtitle &&
15− lhs.people == rhs.people &&
16− lhs.hashtags == rhs.hashtags)
17− }
18−
11+class Channel {
1912 var title = String()
2013 var subtitle = String()
2114
2215 var hashtags: [String] = []
2316 var people: [String] = []
2417
25− var posts: [Model.Posts] = []
18+ var posts: [Post] = []
2619
27− init(title: String, subtitle: String = "none", hashtags: [String] = [], people: [String] = [], posts: [Model.Posts])
20+ init(title: String, subtitle: String, hashtags: [String], people: [String], posts: [Post])
2821 {
2922 self.title = title
3023 self.subtitle = subtitle
GDproject/Simple model/CompletionTree.swiftdeleted−44
@@ -1,44 +0,0 @@
1−//
2−// CompletionTree.swift
3−// GDproject
4−//
5−// Created by cstore on 01/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import Foundation
10−
11−
12−struct CompletionTree: Codable {
13− var value: String?
14− var subtree: [String : CompletionTree]
15−
16− static func getCompletion(tree: CompletionTree, word: String) -> [String] {
17− if word == "" {
18− return getValues(tree: tree)
19− }
20−
21− let character = String(word.first!)
22−
23− if tree.subtree[character] == nil {
24− return []
25− } else {
26− return getCompletion(tree: tree.subtree[character]!, word: String(word.dropFirst()))
27− }
28− }
29−
30− static func getValues(tree: CompletionTree) -> [String]
31− {
32− var out = [String]()
33−
34− if let treeVal = tree.value {
35− out.append(treeVal)
36− }
37−
38− for (_, subtree) in tree.subtree {
39− out += getValues(tree: subtree)
40− }
41−
42− return out
43− }
44−}
GDproject/Simple model/Model.swiftdeleted−1150
@@ -1,1150 +0,0 @@
1−//
2−// Model.swift
3−// GDproject
4−//
5−// Created by cstore on 23/02/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import Foundation
10−import UIKit
11−import Alamofire
12−
13−enum ResultR: Int {
14− case internalServerError = 500
15− case exceededContent = 470
16− case longContent = 471
17− case incorrectContent = 472
18− case impossibleContent = 473
19− case invalidTocken = 498
20− case alreadyRegistered = 409
21− case invalidCode = 403
22− case badAccess = 400
23− case tooMuchToAdd = 406
24− case notFound = 404
25− case success1 = 204
26− case success = 200
27−}
28−
29−class Model{
30−
31− static let invalidTocken = 498
32−
33− static var hashTagTree: CompletionTree?
34−
35− private static var isValidTocken: ((Int)->())? = { responce in
36− print(responce)
37− if responce == invalidTocken {
38−
39− DataStorage.standard.setIsLoggedIn(value: false, with: 0)
40− (UIApplication.shared.delegate as! AppDelegate).relaunch()
41−
42− Model.logout {
43− print("Logout Is Successful")
44− }
45− }
46− }
47−
48− private static let baseUrl = "https://valera-denis.herokuapp.com"
49− static let decoder = JSONDecoder()
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")!
55− static let authenticationURL = URL(string:"\(baseUrl)/authentication/login")!
56− static let logOutURL = URL(string:"\(baseUrl)/authentication/logout")!
57− static let postsLastURL = URL(string:"\(baseUrl)/posts/last")!
58− static let postsForUserURL = URL(string:"\(baseUrl)/posts/forUser")!
59− static let postsPublishURL = URL(string:"\(baseUrl)/posts/publish")!
60− static let usersURL = URL(string:"\(baseUrl)/users")!
61− static let usersAllURL = URL(string:"\(baseUrl)/users/all")!
62− static let usersUpdateURL = URL(string:"\(baseUrl)/users/update")!
63− static let channelsGetURL = URL(string: "\(baseUrl)/channels/get")!
64− static let channelsUpdateURL = URL(string: "\(baseUrl)/channels/update")!
65− static let channelsListURL = URL(string: "\(baseUrl)/channels")!
66− static let channelsCreateURL = URL(string: "\(baseUrl)/channels/create")!
67− static let channelsDeleteURL = URL(string: "\(baseUrl)/channels/delete")!
68− static let channelsGetAnonURL = URL(string: "\(baseUrl)/channels/getAnonymous")!
69− static let complexURL = URL(string: "\(baseUrl)/complex")!
70− static let hashTagTreeURL = URL(string: "\(baseUrl)/tags/completions")!
71− static let createGroupChatURL = URL(string: "\(baseUrl)/chats/createGroupChat")!
72− static let chatsGetAllURL = URL(string: "\(baseUrl)/chats/getAll")!
73− static let getGroupChatURL = URL(string: "\(baseUrl)/chats/getGroupChat")!
74− static let leaveGroupChatURL = URL(string: "\(baseUrl)/chats/leaveGroupChat")!
75− static let updateGroupChatURL = URL(string: "\(baseUrl)/chats/updateGroupChat")!
76− static let messagesGetGroupChatURL = URL(string: "\(baseUrl)/messages/get/groupChat")! //r
77− static let messagesSendURL = URL(string: "\(baseUrl)/messages/send")!
78− static let messagesGetUserChatURL = URL(string: "\(baseUrl)/messages/get/userChat")!
79− static let facultySearchURL = URL(string: "\(baseUrl)/faculty/search")!
80−
81−
82− struct QueryPosts<T: Codable>: Codable {
83− var users: [Int: Users]
84− var response: [T]
85− }
86−
87− struct Posts: Codable {
88−
89− var body: [Attachments]
90− var authorId: Int
91− var id: Int
92− var user: Model.Users?
93− var updated: String
94− var tags: [String]
95−
96− init(body: [Attachments], authorId: Int, id: Int, date: String,tags: [String]) {
97− self.body = body
98− self.authorId = authorId
99− self.id = id
100− self.updated = date
101− self.tags = tags
102− }
103−
104− init(body: [Attachments], authorId: Int, id: Int, user: Model.Users, date: String, tags: [String]) {
105− self.body = body
106− self.authorId = authorId
107− self.id = id
108− self.user = user
109− self.updated = date
110− self.tags = tags
111− }
112−
113− func convertDateFormatter() -> String
114− {
115−
116− let dateFormatter = DateFormatter()
117− dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"//this your string date format
118− dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
119− let date = dateFormatter.date(from: updated)
120−
121− dateFormatter.dateFormat = "MMM d, yyyy HH:mm" ///this is what you want to convert format
122− dateFormatter.timeZone = NSTimeZone.local
123− let timeStamp = dateFormatter.string(from: date!)
124−
125− return timeStamp
126− }
127− }
128−
129− struct CreatedPost: Codable {
130− var body = [Attachments]()
131− var tags = [String]()
132−
133− enum CodingKeys: String, CodingKey {
134− case body
135− case tags
136− }
137−
138− func encode(to encoder: Encoder) throws {
139− var container = encoder.container(keyedBy: CodingKeys.self)
140− try container.encode(body, forKey: .body)
141− try container.encode(tags, forKey: .tags)
142− }
143− }
144−
145− struct Users: Codable{
146−
147− var middleName: String
148− var lastName: String
149− var firstName: String
150− var id: Int
151− var faculty: Faculty
152− var email: String
153−
154− func fullName() -> String {
155− return "\(firstName) \(lastName)"
156− }
157− }
158−
159− struct Attachments: Codable {
160− var markdown: String
161−
162− init(markdown: String) {
163− self.markdown = markdown
164− }
165−
166− enum CodingKeys: String, CodingKey {
167− case markdown
168− }
169−
170− func encode(to encoder: Encoder) throws {
171− var container = encoder.container(keyedBy: CodingKeys.self)
172− try container.encode(markdown, forKey: .markdown)
173− }
174− }
175−
176− struct Channels: Codable {
177−
178− // static var fullTags = Set<String>()
179− static var fullPeople = [Users]()
180− static var fullPeopleDict = [Int:Users]()
181−
182− var people: [Int]
183− var name: String
184− var id: Int?
185− var tags: [String]
186−
187− init(people: [Int], name: String, id: Int, tags: [String]) {
188− self.id = id
189− self.people = people
190− self.tags = tags
191− self.name = name
192− }
193−
194− init(people: [Int], name: String, tags: [String]) {
195− self.people = people
196− self.tags = tags
197− self.name = name
198− }
199−
200− enum CodingKeys: String, CodingKey {
201− case people
202− case name
203− case id
204− case tags
205− }
206−
207− func encode(to encoder: Encoder) throws {
208− var container = encoder.container(keyedBy: CodingKeys.self)
209− try container.encode(people, forKey: .people)
210− try container.encode(name, forKey: .name)
211− try container.encode(id, forKey: .id)
212− try container.encode(tags, forKey: .tags)
213− }
214− }
215−
216− struct AuthStatus: Codable {
217− var userStatus: String
218−
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)
258−
259− request.httpMethod = "POST"
260− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
261−
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)
287− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
288−
289− AF.request(request).response { (responce) in
290−
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 {
302− completion(false)
303− }
304− }
305− }
306−
307− // yes or no
308− static func authenticateMe(completion: @escaping ((Bool)->())){
309− var request = URLRequest(url: authMeURL)
310− request.httpMethod = "POST"
311−
312− AF.request(request).response { (responce) in
313−
314− guard let statusCode = responce.response?.statusCode else { completion(false); return }
315− isValidTocken?(statusCode)
316−
317− if let code = responce.response?.statusCode, code == 498 {
318− return
319− }
320−
321− guard let json = responce.data else { return }
322− guard let personId = Int(String(data: json, encoding: String.Encoding.utf8)!) else {
323− completion(false)
324− return
325− }
326−
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
346−
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 }
356−
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− }
364−
365− completion(res)
366− }
367− }
368−
369− struct GeneralRequest<T: Codable>: Codable
370− {
371− var direction: String
372− var limit: Int
373− var exclusiveFrom: Int?
374− var request: T
375−
376− init(direction: String = "backward", limit: Int, exclusiveFrom: Int?, request: T) {
377− self.direction = direction
378− self.limit = limit
379− self.exclusiveFrom = exclusiveFrom
380− self.request = request
381− }
382−
383− enum CodingKeys: String, CodingKey {
384− case limit
385− case exclusiveFrom
386− case request
387− case direction
388− }
389−
390− func encode(to encoder: Encoder) throws {
391− var container = encoder.container(keyedBy: CodingKeys.self)
392− try container.encode(limit, forKey: .limit)
393− try container.encode(exclusiveFrom, forKey: .exclusiveFrom)
394− try container.encode(request, forKey: .request)
395− try container.encode(direction, forKey: .direction)
396− }
397− }
398−
399− static func getLast(on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
400− {
401− let postRequest = GeneralRequest<[Int]>(limit: limit, exclusiveFrom: pointInTime, request: [])
402−
403− var request = URLRequest(url: postsLastURL)
404− request.httpBody = try? JSONEncoder().encode(postRequest)
405− request.httpMethod = "POST"
406−
407− // insert json data to the request
408− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
409−
410− AF.request(request).responseJSON {
411− (response) in
412−
413− isValidTocken?(response.response?.statusCode ?? 498)
414−
415− if let code = response.response?.statusCode, code == 498 {
416− return
417− }
418−
419− guard let json = response.data else { return }
420−
421− guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { print("no")
422− return }
423−
424− idUser = newQueery.users
425− completion((newQueery.users, newQueery.response))
426− }
427− }
428−
429−
430− static func createAndPublish(body: [Attachments], tags: [String], completion: @escaping ((ResultR)->())){
431− let jsonUpd = CreatedPost(body: body, tags: tags)
432− var request = URLRequest(url: postsPublishURL)
433−
434− request.httpMethod = "POST"
435−
436− // insert json data to the request
437− request.httpBody = try? JSONEncoder().encode(jsonUpd)
438−
439− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
440− AF.request(request).response {
441− (response) in
442−
443− isValidTocken?(response.response?.statusCode ?? 498)
444−
445− if let code = response.response?.statusCode, code == 498 {
446− return
447− }
448−
449− if let code = response.response?.statusCode,
450− let result = ResultR(rawValue: code)
451− {
452− completion(result)
453− } else {
454− completion(.internalServerError)
455− }
456− }
457− }
458−
459−// static func requestForPosts(limit: Int = 10, ){
460−//
461−// }
462−
463− static func getPostsForUser(for limit: Int = 10, from pointInTime: Int? = nil, with id: Int, completion: @escaping (([Posts])->()))
464− {
465− let postsRequest = GeneralRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: id)
466−
467− let jsonData = try? JSONEncoder().encode(postsRequest)
468−
469− var request = URLRequest(url: postsForUserURL)
470− request.httpMethod = "POST"
471−
472− // insert json data to the request
473− request.httpBody = jsonData
474− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
475−
476− AF.request(request).responseJSON {
477− (response) in
478−
479− isValidTocken?(response.response?.statusCode ?? 498)
480−
481− if let code = response.response?.statusCode, code == 498 {
482− return
483− }
484−
485− guard let json = response.data else { return }
486−
487− guard let newPost = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
488−
489− completion(newPost.response)
490− }
491− }
492−
493− static var idUser: [Int:Users] = [:]
494−
495− static func getUsers(for ids: [Int], completion: @escaping (([Int:Users])->())){
496− let json = "\(Set(ids))"
497−
498− var request = URLRequest(url: usersURL)
499−
500− request.httpMethod = "POST"
501−
502− // insert json data to the request
503− request.httpBody = json.data(using: .utf8)
504− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
505−
506− AF.request(request).responseJSON {
507− (response) in
508−
509− isValidTocken?(response.response?.statusCode ?? 498)
510−
511− if let code = response.response?.statusCode, code == 498 {
512− return
513− }
514−
515− guard let json = response.data else { return }
516−
517− guard let users = try? decoder.decode([Users].self, from: json) else { return }
518−
519− var dict: [Int:Users] = [:]
520−
521− users.forEach({ (user) in
522− dict[user.id] = user
523− })
524−
525− completion(dict)
526− }
527− }
528−
529− // get channel (with id): in responce -- PostQuery
530− static func getChannel(with channelId: Int, on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
531− {
532− let postRequest = GeneralRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: channelId)
533− let jsonData = try? JSONEncoder().encode(postRequest)
534−
535− var request = URLRequest(url: channelsGetURL)
536− request.httpMethod = "POST"
537−
538− // insert json data to the request
539− request.httpBody = jsonData
540− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
541−
542− AF.request(request).responseJSON {
543− (response) in
544−
545− isValidTocken?(response.response?.statusCode ?? 498)
546−
547− if let code = response.response?.statusCode, code == 498 {
548− return
549− }
550−
551− guard let json = response.data else { return }
552−
553− guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
554−
555− idUser = newQueery.users
556− completion((newQueery.users, newQueery.response))
557− }
558− }
559−
560−
561− static func createChannel(with channel: Channels, completion: @escaping ((ResultR)->())) {
562−
563− var request = URLRequest(url: channelsCreateURL)
564− request.httpMethod = "POST"
565− request.httpBody = try? JSONEncoder().encode(channel)
566−
567− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
568− AF.request(request).response {
569− (response) in
570−
571− isValidTocken?(response.response?.statusCode ?? 498)
572−
573− if let code = response.response?.statusCode, let result = ResultR(rawValue: code) {
574− completion(result)
575− return
576− }
577−
578− completion(ResultR.internalServerError)
579− }
580−
581− }
582−
583− static func channelsList(completion: @escaping (([Channels])->())){
584− var request = URLRequest(url: channelsListURL)
585− request.httpMethod = "POST"
586− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
587−
588− AF.request(request).responseJSON { (response) in
589−
590− isValidTocken?(response.response?.statusCode ?? 498)
591− if let code = response.response?.statusCode, code == 498 {
592− return
593− }
594−
595− guard let json = response.data else { return }
596−
597− guard let channelsList = try? decoder.decode([Channels].self, from: json) else { return }
598−
599− completion(channelsList)
600− }
601− }
602−
603− static func channelsDelete(by id: Int, completion: @escaping(()->())){
604− var request = URLRequest(url: channelsDeleteURL)
605− request.httpMethod = "POST"
606− request.httpBody = "\(id)".data(using: .utf8)
607− print("\(id)")
608− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
609−
610− AF.request(request).response { (response) in
611− isValidTocken?(response.response?.statusCode ?? 498)
612− if let code = response.response?.statusCode, code == 498 {
613− return
614− }
615− }
616− completion()
617− }
618−
619− static func updateChannel(with channel: Channels) {
620−
621− var request = URLRequest(url: channelsUpdateURL)
622− request.httpMethod = "POST"
623− request.httpBody = try? JSONEncoder().encode(channel)
624−
625− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
626− AF.request(request).response {
627− (response) in
628−
629− isValidTocken?(response.response?.statusCode ?? 498)
630− if let code = response.response?.statusCode, code == 498 {
631− return
632− }
633− }
634− }
635−
636− static func usersAllGet() {
637− var request = URLRequest(url: usersAllURL)
638− request.httpMethod = "POST"
639−
640− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
641− AF.request(request).response {
642− (response) in
643− guard let json = response.data else { return }
644−
645− guard let users = try? decoder.decode([Users].self, from: json) else { return }
646−
647− Channels.fullPeople = users
648− Channels.fullPeopleDict = users.reduce([Int: Users]()) { (dict, person) -> [Int: Users] in
649− var dict = dict
650− dict[person.id] = person
651− return dict
652− }
653−
654− isValidTocken?(response.response?.statusCode ?? 498)
655− if let code = response.response?.statusCode, code == 498 {
656− return
657− }
658− }
659− }
660−
661− struct AnonymousChannel: Codable {
662−
663− var limit = 10
664− var request: RequestPeopleTags
665−
666− enum CodingKeys: String, CodingKey {
667− case limit
668− case request
669− }
670−
671− init(people: [Int], tags: [String]) {
672− self.request = RequestPeopleTags(people: people, tags: tags)
673− }
674−
675− func encode(to encoder: Encoder) throws {
676− var container = encoder.container(keyedBy: CodingKeys.self)
677− try container.encode(limit, forKey: .limit)
678− try container.encode(request, forKey: .request)
679− }
680−
681− struct RequestPeopleTags: Codable {
682−
683− var people: [Int]
684− var tags: [String]
685−
686− init(people: [Int], tags: [String]) {
687− self.people = people
688− self.tags = tags
689− }
690−
691− func encode(to encoder: Encoder) throws {
692− var container = encoder.container(keyedBy: CodingKeys.self)
693− try container.encode(people, forKey: .people)
694− try container.encode(tags, forKey: .tags)
695− }
696−
697− enum CodingKeys: String, CodingKey {
698− case people
699− case tags
700− }
701−
702− }
703− }
704− /*
705− {
706− "limit": 11,
707− "request": {
708− "people": [
709− 2,
710− 7,
711− 8
712− ],
713− "tags": [
714− "thisIsHashTag",
715− "thisIsAlsoHashTag"
716− ]
717− }
718− }
719− */
720− static func getAnonymousChannel(by anonymousChannel: Model.Channels, exclusiveFrom: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->())){
721−
722− let req = GeneralRequest<Model.Channels>(limit: 10, exclusiveFrom: exclusiveFrom, request: anonymousChannel)
723−
724− var request = URLRequest(url: channelsGetAnonURL)
725− request.httpMethod = "POST"
726− request.httpBody = try? JSONEncoder().encode(req)
727−
728− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
729− AF.request(request).response {
730− (response) in
731−
732− isValidTocken?(response.response?.statusCode ?? 498)
733− if let code = response.response?.statusCode, code == 498 {
734− return
735− }
736−
737− guard let json = response.data else { return }
738−
739− guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
740− completion((newQueery.users, newQueery.response))
741− }
742− }
743−
744− static func getCompl(completion: @escaping ((CompletionTree)->())) {
745−
746− AF.request(URLRequest(url: hashTagTreeURL)).responseJSON {
747− (response) in
748− isValidTocken?(response.response?.statusCode ?? 498)
749− if let code = response.response?.statusCode, code == 498 {
750− return
751− }
752− guard let json = response.data else { return }
753− guard let tree = try? decoder.decode(CompletionTree.self, from: json) else { return }
754− completion(tree)
755− }
756− }
757−
758− static func getChatAll(limit: Int = 10, exclusiveFrom: Int? = nil, request: [Int] = [], completion: @escaping ((([Dialog],[Int:Model.Users]))->()))
759− {
760− let req = GeneralRequest<[Int]>(limit: limit, exclusiveFrom: exclusiveFrom, request: request)
761− var request = URLRequest(url: chatsGetAllURL)
762− request.httpMethod = "POST"
763− request.httpBody = try? JSONEncoder().encode(req)
764− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
765−
766− AF.request(request).responseJSON { response in
767− isValidTocken?(response.response?.statusCode ?? 498)
768−
769− if let code = response.response?.statusCode, code == 498 {
770− return
771− }
772−
773− guard let json = response.data else { return }
774− let dialogs = try! decoder.decode(QueryPosts<Dialog>.self, from: json)
775−
776− completion((dialogs.response,dialogs.users))
777− }
778− }
779−
780− enum Dialog: Codable
781− {
782− case groupChat(GroupChat)
783− case userChat(UserChat)
784−
785− private enum DialogKeys: CodingKey{
786− case groupChat
787− case userChat
788− }
789−
790− init(from decoder: Decoder) throws {
791− let container = try decoder.container(keyedBy: DialogKeys.self)
792− if container.contains(.groupChat){
793− self = .groupChat(try GroupChat(from: container.superDecoder(forKey: .groupChat)))
794− } else if container.contains(.userChat){
795− self = .userChat(try UserChat(from: container.superDecoder(forKey: .userChat)))
796− } else {
797− throw DecodingError.keyNotFound(DialogKeys.groupChat, DecodingError.Context(codingPath: container.codingPath, debugDescription: "hz"))
798− }
799− }
800−
801− func encode(to encoder: Encoder) throws {
802− var container = encoder.container(keyedBy: DialogKeys.self)
803− switch self{
804− case .groupChat(let chat):
805− try chat.encode(to: container.superEncoder(forKey: .groupChat))
806− case .userChat(let chat):
807− try chat.encode(to: container.superEncoder(forKey: .userChat))
808− }
809− }
810− }
811−
812− struct GroupChat: Codable {
813− var group: Group
814− var lastMessage: LastMessage?
815−
816−
817− init(group: Group, lastMessage: LastMessage? = nil) {
818− self.group = group
819− self.lastMessage = lastMessage
820− }
821− }
822−
823− struct UserChat: Codable {
824− var user: Int
825− var lastMessage: LastMessage?
826−
827− init(user: Int, lastMessage: LastMessage? = nil) {
828− self.user = user
829− self.lastMessage = lastMessage
830− }
831− }
832−
833− struct Group: Codable {
834− var users: [Int: UserPermission]
835− var name: String
836− var id: Int
837−
838− init(users: [Int: UserPermission] = [:], name: String = "", id: Int) {
839− self.id = id
840− self.users = users
841− self.name = name
842− }
843− }
844−
845− struct UserPermission: Codable {
846− var isAdmin: Bool
847− }
848−
849− struct LastMessage: Codable {
850− var body: Attachments
851− var destination: MessageDestination
852− var time: String
853− var author: Int
854− var id: Int
855−
856− enum MessageCodingKeys: CodingKey{
857− case user
858− case group
859− case body
860− case time
861− case author
862− case id
863− }
864−
865− init(from decoder: Decoder) throws
866− {
867− let container = try decoder.container(keyedBy: MessageCodingKeys.self)
868− time = try container.decode(String.self, forKey: .time)
869− body = try container.decode(Attachments.self, forKey: .body)
870− author = try container.decode(Int.self, forKey: .author)
871− id = try container.decode(Int.self, forKey: .id)
872−
873− if container.contains(.user){
874− destination = MessageDestination.userChatDestination(try Int(from: container.superDecoder(forKey: .user)))
875− } else if container.contains(.group){
876− destination = MessageDestination.groupChatDestination(try Int(from: container.superDecoder(forKey: .group)))
877− } else {
878− throw DecodingError.keyNotFound(MessageCodingKeys.group, DecodingError.Context(codingPath: container.codingPath, debugDescription: "hz gr"))
879− }
880− }
881−
882− func encode(to encoder: Encoder) throws {
883− var container = encoder.container(keyedBy: MessageCodingKeys.self)
884−
885− try container.encode(time, forKey: .time)
886− try container.encode(id, forKey: .id)
887− try container.encode(author, forKey: .author)
888− try container.encode(body, forKey: .body)
889−
890− switch destination {
891− case .userChatDestination(let uId):
892− try uId.encode(to: container.superEncoder(forKey: .user))
893− case .groupChatDestination(let gId):
894− try gId.encode(to: container.superEncoder(forKey: .group))
895− }
896− }
897− }
898−
899− enum MessageDestination: Codable
900− {
901− func encode(to encoder: Encoder) throws
902− {
903− var container = encoder.container(keyedBy: MessCodingKeys.self)
904− switch self {
905− case .userChatDestination(let uId):
906− try uId.encode(to: container.superEncoder(forKey: .user))
907− case .groupChatDestination(let gId):
908− try gId.encode(to: container.superEncoder(forKey: .group))
909− }
910− }
911−
912− init(from decoder: Decoder) throws
913− {
914− let container = try decoder.container(keyedBy: MessCodingKeys.self)
915− if container.contains(.user){
916− self = .userChatDestination(try Int(from: container.superDecoder(forKey: .user)))
917− } else if container.contains(.group){
918− self = .groupChatDestination(try Int(from: container.superDecoder(forKey: .group)))
919− } else {
920− throw DecodingError.keyNotFound(MessCodingKeys.group, DecodingError.Context(codingPath: container.codingPath, debugDescription: "hz gr"))
921− }
922− }
923−
924− enum MessCodingKeys: CodingKey{
925− case user
926− case group
927− }
928−
929− case userChatDestination(Int)
930− case groupChatDestination(Int)
931−
932− }
933−
934− static func createGroupChat(from group: Group, completion: @escaping ((Int)->())) {
935− let req = group
936− var request = URLRequest(url: createGroupChatURL)
937− request.httpMethod = "POST"
938− request.httpBody = try? JSONEncoder().encode(req)
939− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
940−
941− AF.request(request).response { (response) in
942−
943− isValidTocken?(response.response?.statusCode ?? 498)
944− if let code = response.response?.statusCode, code == 498 {
945− return
946− }
947−
948− guard let json = response.data else { return }
949− let stringInt = String.init(data: json, encoding: String.Encoding.utf8)
950− let intId = Int.init(stringInt!)
951−
952− completion(intId!)
953− }
954− }
955−
956− static func getMessagesFor(typeOfChat: Model.Dialog, chat id: Int, exclusiveFrom: Int? = nil, limit l: Int = 25, direction: String = "backward", completion: @escaping (([LastMessage])->()))
957− {
958− let req = GeneralRequest<Int>(direction: direction, limit: l, exclusiveFrom: exclusiveFrom, request: id)
959− var request: URLRequest?
960−
961− switch typeOfChat {
962− case .groupChat:
963− request = URLRequest(url: messagesGetGroupChatURL)
964− case .userChat:
965− request = URLRequest(url: messagesGetUserChatURL)
966− }
967−
968− request!.httpMethod = "POST"
969− request!.httpBody = try? JSONEncoder().encode(req)
970− request!.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
971−
972− AF.request(request!).response { (response) in
973−
974− isValidTocken?(response.response?.statusCode ?? 498)
975− if let code = response.response?.statusCode, code == 498 {
976− return
977− }
978−
979− guard let json = response.data else { return }
980− guard let messages = try? decoder.decode([LastMessage].self, from: json) else { return }
981−
982− completion(messages)
983− }
984− }
985−
986− static func leaveGroupChat(id: Int, completion: @escaping (()->()))
987− {
988− var request = URLRequest(url: leaveGroupChatURL)
989− request.httpMethod = "POST"
990− request.httpBody = "\(id)".data(using: .utf8)
991− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
992−
993− AF.request(request).response { (response) in
994− isValidTocken?(response.response?.statusCode ?? 498)
995−
996− if let code = response.response?.statusCode, code == 498 {
997− return
998− }
999− }
1000−
1001− completion()
1002− }
1003−
1004− static func updateGroupChat(with group: Model.Group)
1005− {
1006− var request = URLRequest(url: updateGroupChatURL)
1007− request.httpMethod = "POST"
1008− request.httpBody = try? JSONEncoder().encode(group)
1009− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
1010−
1011− AF.request(request).response { (response) in
1012− isValidTocken?(response.response?.statusCode ?? 498)
1013−
1014− if let code = response.response?.statusCode, code == 498 {
1015− return
1016− }
1017− }
1018−
1019− // completion()
1020− }
1021−
1022− struct SendMessage: Codable {
1023− var body: Attachments
1024− var destination: MessageDestination
1025−
1026− init(from decoder: Decoder) throws
1027− {
1028− let container = try decoder.container(keyedBy: LastMessage.MessageCodingKeys.self)
1029− body = try container.decode(Attachments.self, forKey: .body)
1030−
1031− if container.contains(.user){
1032− destination = MessageDestination.userChatDestination(try Int(from: container.superDecoder(forKey: .user)))
1033− } else if container.contains(.group){
1034− destination = MessageDestination.groupChatDestination(try Int(from: container.superDecoder(forKey: .group)))
1035− } else {
1036− throw DecodingError.keyNotFound(LastMessage.MessageCodingKeys.group, DecodingError.Context(codingPath: container.codingPath, debugDescription: "hz gr1"))
1037− }
1038− }
1039−
1040− func encode(to encoder: Encoder) throws {
1041− var container = encoder.container(keyedBy: LastMessage.MessageCodingKeys.self)
1042− try container.encode(body, forKey: .body)
1043−
1044− switch destination {
1045− case .userChatDestination(let uId):
1046− try uId.encode(to: container.superEncoder(forKey: .user))
1047− case .groupChatDestination(let gId):
1048− try gId.encode(to: container.superEncoder(forKey: .group))
1049− }
1050− }
1051−
1052− init(body: Attachments, destination: MessageDestination)
1053− {
1054− self.body = body
1055− self.destination = destination
1056− }
1057− }
1058−
1059− static func sendMessage(message: SendMessage, completion: @escaping ((ResultR)->())){
1060−
1061− var request = URLRequest(url: messagesSendURL)
1062− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
1063− request.httpMethod = "POST"
1064− request.httpBody = try? JSONEncoder().encode(message)
1065−
1066− AF.request(request).response { (response) in
1067− isValidTocken?(response.response?.statusCode ?? 498)
1068−
1069− if let code = response.response?.statusCode, code == 498 {
1070− return
1071− }
1072−
1073− if let result = ResultR(rawValue: response.response!.statusCode){
1074− completion(result)
1075− } else {
1076− completion(.internalServerError)
1077− }
1078− }
1079− }
1080−
1081− struct Faculty: Codable
1082− {
1083−
1084− var path: String
1085− var url: String
1086− var campusName: String
1087− var campusCode: String
1088− var name: String
1089− var tags: [String]
1090− var address: String
1091−
1092− }
1093−
1094− static func searchFaculty(string: String, completion: @escaping (([Model.Faculty])->()))
1095− {
1096− var request = URLRequest(url: facultySearchURL)
1097− request.httpMethod = "POST"
1098− request.httpBody = string.data(using: .utf8)
1099− request.setValue("text/plain;charset=utf-8", forHTTPHeaderField: "Content-Type")
1100−
1101− AF.request(request).response { (response) in
1102− isValidTocken?(response.response?.statusCode ?? 498)
1103−
1104− if let code = response.response?.statusCode, code == 498 {
1105− return
1106− }
1107−
1108− guard let json = response.data else { return }
1109− guard let faculties = try? decoder.decode([Faculty].self, from: json) else { return }
1110−
1111− completion(faculties)
1112− }
1113− }
1114−
1115− static func userUpdate(with newUser: NewRegistration, completion: @escaping ((Bool)->())) {
1116− var request = URLRequest(url: usersUpdateURL)
1117− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
1118− request.httpMethod = "POST"
1119− request.httpBody = try? JSONEncoder().encode(newUser)
1120−
1121− AF.request(request).response { (response) in
1122− isValidTocken?(response.response?.statusCode ?? 498)
1123−
1124− if let code = response.response?.statusCode, code == 498 {
1125− return
1126− }
1127−
1128− if let code = response.response?.statusCode, code != 204{
1129− completion (false)
1130− } else {
1131− completion(true)
1132− }
1133− }
1134− }
1135−
1136− static func deactivateAll(completion: @escaping (()->())){
1137− var request = URLRequest(url: deactivateURL)
1138− request.httpMethod = "DELETE"
1139−
1140− AF.request(request).response { (responce) in
1141− isValidTocken?(responce.response?.statusCode ?? 498)
1142−
1143− if let code = responce.response?.statusCode, code == 498 {
1144− return
1145− }
1146−
1147− completion()
1148− }
1149− }
1150−}
GDproject/Simple model/Post.swift+26
@@ -9,6 +9,31 @@
99import Foundation
1010import UIKit
1111
12+struct Post {
13+ var dataArray: [Media]
14+ var fromUser: User
15+ var atDate: String
16+ var comments: [Comment] = []
17+
18+ var hashtags: [String] = ["ФКН", "Подбельский", "НИУВШЭ", "Шершаков", "ПАД", "Интересное","Мемы","Забавное","Учеба","Наука"]
19+
20+ init(dataArray: [Media], from: User, date: String, comments: [Comment] = [])
21+ {
22+ self.dataArray = dataArray
23+ fromUser = from
24+ atDate = date
25+ self.comments = comments
26+ }
27+
28+ init(dataArray: [Media]) {
29+ self.dataArray = dataArray
30+ fromUser = User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна")
31+ atDate = "23.03.19 в 23:33"
32+ }
33+
34+}
35+
36+
1237enum Media{
1338 case text(String)
1439 case image([UIImage])
@@ -16,6 +41,7 @@ enum Media{
1641}
1742
1843struct Comment {
44+ var from: User
1945 var atTime: String
2046 var withData: String
2147}
GDproject/Simple model/User.swiftnew file+41
@@ -0,0 +1,41 @@
1+//
2+// User.swift
3+// NewsFeed
4+//
5+// Created by cstore on 12/01/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import Foundation
10+import UIKit
11+
12+struct User {
13+ //var photo: UIImage? = #imageLiteral(resourceName: "image")
14+ var login: String
15+ var id: Int
16+ var fullName: String
17+ var initials: (surname: String, name: String, optional: String?) = ("Богомазова","Вероника","Львовна")
18+ var placeOfWork: String?
19+ var faculty: String?
20+ let posts: [Post] = []
21+
22+
23+ init(name: String, id: Int, fullName: String) {
24+ self.login = name
25+ self.id = id
26+ self.fullName = fullName
27+ }
28+
29+ init(surname: String, name: String, optional: String?, emailName: String, id: Int, place: String?, faculty: String?)
30+ {
31+ self.id = id
32+ self.login = emailName
33+ self.initials = (surname, name, optional)
34+
35+ self.fullName = "\(surname) \(name) \(optional ?? "")"
36+ self.placeOfWork = place
37+ if let f = faculty {
38+ self.faculty = f
39+ }
40+ }
41+}
GDproject/Supporting files/AppDelegate.swift+28−20
@@ -11,29 +11,37 @@ import UIKit
1111@UIApplicationMain
1212class AppDelegate: UIResponder, UIApplicationDelegate {
1313
14−
1514 var window: UIWindow?
16− var appCoordinator: ApplicationCoordinator!
17−
18−
19− func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
20− {
21− window = UIWindow(frame: UIScreen.main.bounds)
22− window?.makeKeyAndVisible()
23−
24− // window?.rootViewController = UINavigationController()
25− Model.getCompl { (complTree) in
26− Model.hashTagTree = complTree
27− }
28−
29− appCoordinator = ApplicationCoordinator(window: window!)
30− appCoordinator.start()
31−
15+
16+
17+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18+ // Override point for customization after application launch.
19+// window = UIWindow(frame: UIScreen.main.bounds)
20+// window?.makeKeyAndVisible()
21+// window?.rootViewController = MainController()
3222 return true
3323 }
34−
35− func relaunch(){
36− appCoordinator.start()
24+
25+ func applicationWillResignActive(_ application: UIApplication) {
26+ // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
27+ // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
28+ }
29+
30+ func applicationDidEnterBackground(_ application: UIApplication) {
31+ // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
32+ // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33+ }
34+
35+ func applicationWillEnterForeground(_ application: UIApplication) {
36+ // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
37+ }
38+
39+ func applicationDidBecomeActive(_ application: UIApplication) {
40+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
41+ }
42+
43+ func applicationWillTerminate(_ application: UIApplication) {
44+ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
3745 }
3846}
3947
GDproject/Supporting files/Assets.xcassets/1.imageset/1.pdfdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/1.imageset/Contents.jsondeleted−25
@@ -1,25 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "1.pdf",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− },
21− "properties" : {
22− "template-rendering-intent" : "template",
23− "preserves-vector-representation" : true
24− }
25−}
GDproject/Supporting files/Assets.xcassets/2.imageset/2.pdfdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/2.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "2.pdf",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/3.imageset/3.pdfdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/3.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "3.pdf",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/4.imageset/4.pdfdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/4.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "4.pdf",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/42.imageset/42.pngdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/42.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "42.png",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/5.imageset/5.pdfdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/5.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "5.pdf",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/5051.imageset/5051.pngdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/5051.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "5051.png",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/69.imageset/69.pngdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/69.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "69.png",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/9.imageset/9.pngdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/9.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "9.png",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/chat.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "chat.pdf",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/chat.imageset/chat.pdfdeleted

Binary file not shown.

GDproject/Supporting files/Assets.xcassets/share.imageset/Contents.jsondeleted−21
@@ -1,21 +0,0 @@
1−{
2− "images" : [
3− {
4− "idiom" : "universal",
5− "filename" : "share.png",
6− "scale" : "1x"
7− },
8− {
9− "idiom" : "universal",
10− "scale" : "2x"
11− },
12− {
13− "idiom" : "universal",
14− "scale" : "3x"
15− }
16− ],
17− "info" : {
18− "version" : 1,
19− "author" : "xcode"
20− }
21−}
GDproject/Supporting files/Assets.xcassets/share.imageset/share.pngdeleted

Binary file not shown.