git.iko.soy/dashared/GDproject
on 8cecd53 help sign in
Cartfile+2−5
since splitsnapshots
unifiedsplit
@@ -2,8 +2,5 @@ github "robb/Cartography"
2github "ivanbruel/MarkdownKit"
2github "ivanbruel/MarkdownKit"
3github "roberthein/TinyConstraints"
3github "roberthein/TinyConstraints"
4github "macteo/Marklight"
4github "macteo/Marklight"
5+github "ElaWorkshop/TagListView"
5−github "Alamofire/Alamofire" "5.0.0-beta.5"
6+github "Alamofire/Alamofire" "5.0.0-beta.2"
6−github "52inc/Pulley"
7−github "HeroTransitions/Hero"
8−github "ReactiveCocoa/ReactiveCocoa" ~> 9.0
9−github "ZaidSA/TaggerKit" "bb826a7"
GDproject.xcodeproj/project.pbxproj+58−189
@@ -7,37 +7,19 @@
7 objects = {
7 objects = {
8
8
9/* Begin PBXBuildFile section */
9/* 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 */; };
14 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
10 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
15 123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
11 123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
16 124CC7032221C00C009DF531 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124CC7022221C00C009DF531 /* Model.swift */; };
12 124CC7032221C00C009DF531 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124CC7022221C00C009DF531 /* Model.swift */; };
17− 125A9A8A2285C3DA00513E2A /* CodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A892285C3DA00513E2A /* CodeViewController.swift */; };
13+ 124CC7052221C2BB009DF531 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 124CC7042221C2BA009DF531 /* Alamofire.framework */; };
18− 125A9A8E2286068A00513E2A /* RegisterTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */; };
14+ 124CC7072221C2C3009DF531 /* Alamofire.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 124CC7042221C2BA009DF531 /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
19− 125A9A90228609C500513E2A /* InititalsViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A8F228609C500513E2A /* InititalsViewCell.swift */; };
15+ 1253867D2223DC9F00CC5EA7 /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1253867C2223DC9F00CC5EA7 /* RepeatingTimer.swift */; };
20− 125A9A922286100800513E2A /* FacultyTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A912286100800513E2A /* FacultyTableViewController.swift */; };
21 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57C22171D2A008A3575 /* ProfileViewController.swift */; };
16 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57C22171D2A008A3575 /* ProfileViewController.swift */; };
22 125BD57F22171D73008A3575 /* Extentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57E22171D73008A3575 /* Extentions.swift */; };
17 125BD57F22171D73008A3575 /* Extentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57E22171D73008A3575 /* Extentions.swift */; };
23 125BD5812217314A008A3575 /* NewsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD5802217314A008A3575 /* NewsVC.swift */; };
18 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 */; };
28 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1288B5CD221F1158002BE6B1 /* DataStorage.swift */; };
19 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1288B5CD221F1158002BE6B1 /* DataStorage.swift */; };
29 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */; };
20 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */; };
30 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */; };
21 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 */; };
22+ 1291BE3622218DBF009D3F23 /* LogInCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE3522218DBF009D3F23 /* LogInCoordinator.swift */; };
39− 12CE7D6F227B94B10024B6E8 /* TaggerKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */; };
40− 12CE7D71227B94B50024B6E8 /* TaggerKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
41 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D132221C321600B35452 /* ChannelListController.swift */; };
23 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D132221C321600B35452 /* ChannelListController.swift */; };
42 12D7D135221C42B700B35452 /* ChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D134221C42B700B35452 /* ChannelController.swift */; };
24 12D7D135221C42B700B35452 /* ChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D134221C42B700B35452 /* ChannelController.swift */; };
43 12D7D137221D78E800B35452 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D136221D78E800B35452 /* Channel.swift */; };
25 12D7D137221D78E800B35452 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D136221D78E800B35452 /* Channel.swift */; };
@@ -51,54 +33,38 @@
51 12E36DA1221424EA006FCDD7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36D9F221424EA006FCDD7 /* Main.storyboard */; };
33 12E36DA1221424EA006FCDD7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36D9F221424EA006FCDD7 /* Main.storyboard */; };
52 12E36DA3221424ED006FCDD7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA2221424ED006FCDD7 /* Assets.xcassets */; };
34 12E36DA3221424ED006FCDD7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA2221424ED006FCDD7 /* Assets.xcassets */; };
53 12E36DA6221424ED006FCDD7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA4221424ED006FCDD7 /* LaunchScreen.storyboard */; };
35 12E36DA6221424ED006FCDD7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA4221424ED006FCDD7 /* LaunchScreen.storyboard */; };
36+ 12E36DAF22143D40006FCDD7 /* Cartography.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DAE22143D40006FCDD7 /* Cartography.framework */; };
37+ 12E36DB322143D4E006FCDD7 /* Marklight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB222143D4E006FCDD7 /* Marklight.framework */; };
38+ 12E36DB522143D54006FCDD7 /* TinyConstraints.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */; };
54 12E36DB72214400A006FCDD7 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB62214400A006FCDD7 /* Post.swift */; };
39 12E36DB72214400A006FCDD7 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB62214400A006FCDD7 /* Post.swift */; };
40+ 12E36DB922144016006FCDD7 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB822144016006FCDD7 /* User.swift */; };
41+ 12E36DBD221441D5006FCDD7 /* TinyConstraints.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
42+ 12E36DC0221441DB006FCDD7 /* Marklight.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB222143D4E006FCDD7 /* Marklight.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
43+ 12E36DC2221441E1006FCDD7 /* MarkdownKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
44+ 12E36DC4221441EA006FCDD7 /* Cartography.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DAE22143D40006FCDD7 /* Cartography.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
55 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DC922144635006FCDD7 /* NewPostViewController.swift */; };
45 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DC922144635006FCDD7 /* NewPostViewController.swift */; };
56 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCB22144725006FCDD7 /* PostViewCell.swift */; };
46 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCB22144725006FCDD7 /* PostViewCell.swift */; };
57 12E36DCE22144756006FCDD7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCD22144756006FCDD7 /* Constants.swift */; };
47 12E36DCE22144756006FCDD7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCD22144756006FCDD7 /* Constants.swift */; };
58 12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DD022148122006FCDD7 /* FullPostController.swift */; };
48 12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DD022148122006FCDD7 /* FullPostController.swift */; };
59 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DD422156559006FCDD7 /* MyStackView.swift */; };
49 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 */; };
50+ 12E36DD8221594A9006FCDD7 /* TagListView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DD622159493006FCDD7 /* TagListView.framework */; };
77− 12FDAC98226B61CB00995B4E /* TinyConstraints.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC95226B61C400995B4E /* TinyConstraints.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
51+ 12E36DD9221594A9006FCDD7 /* TagListView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DD622159493006FCDD7 /* TagListView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
78− 12FDAC9B226B652C00995B4E /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC99226B652400995B4E /* ReactiveSwift.framework */; };
52+ 12E36DDB221594B1006FCDD7 /* MarkdownKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB022143D47006FCDD7 /* MarkdownKit.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, ); }; };
82/* End PBXBuildFile section */
53/* End PBXBuildFile section */
83
54
84/* Begin PBXCopyFilesBuildPhase section */
55/* Begin PBXCopyFilesBuildPhase section */
85− 12FDAC85226B5E3700995B4E /* Embed Frameworks */ = {
56+ 12E36DBE221441D5006FCDD7 /* Embed Frameworks */ = {
86 isa = PBXCopyFilesBuildPhase;
57 isa = PBXCopyFilesBuildPhase;
87 buildActionMask = 2147483647;
58 buildActionMask = 2147483647;
88 dstPath = "";
59 dstPath = "";
89 dstSubfolderSpec = 10;
60 dstSubfolderSpec = 10;
90 files = (
61 files = (
91− 12FDAC8E226B5E5000995B4E /* MarkdownKit.framework in Embed Frameworks */,
62+ 12E36DC0221441DB006FCDD7 /* Marklight.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 */,
63+ 124CC7072221C2C3009DF531 /* Alamofire.framework in Embed Frameworks */,
95− 12FDAC8A226B5E4B00995B4E /* Cartography.framework in Embed Frameworks */,
64+ 12E36DC4221441EA006FCDD7 /* Cartography.framework in Embed Frameworks */,
96− 12FDAC9C226B652C00995B4E /* ReactiveSwift.framework in Embed Frameworks */,
97− 12FDAC92226B5E5400995B4E /* Pulley.framework in Embed Frameworks */,
65+ 12E36DD9221594A9006FCDD7 /* TagListView.framework in Embed Frameworks */,
98− 12FDAC8C226B5E4E00995B4E /* Hero.framework in Embed Frameworks */,
66+ 12E36DBD221441D5006FCDD7 /* TinyConstraints.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 */,
67+ 12E36DC2221441E1006FCDD7 /* MarkdownKit.framework in Embed Frameworks */,
102 );
68 );
103 name = "Embed Frameworks";
69 name = "Embed Frameworks";
104 runOnlyForDeploymentPostprocessing = 0;
70 runOnlyForDeploymentPostprocessing = 0;
@@ -106,36 +72,18 @@
106/* End PBXCopyFilesBuildPhase section */
72/* End PBXCopyFilesBuildPhase section */
107
73
108/* Begin PBXFileReference section */
74/* 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>"; };
113 123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
75 123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
114 123E37A6221F1DD700F6E42A /* MainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
76 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>"; };
77 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>"; };
78+ 124CC7042221C2BA009DF531 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; 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>"; };
79+ 1253867C2223DC9F00CC5EA7 /* RepeatingTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer.swift; sourceTree = "<group>"; };
120 125BD57C22171D2A008A3575 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
80 125BD57C22171D2A008A3575 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
121 125BD57E22171D73008A3575 /* Extentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extentions.swift; sourceTree = "<group>"; };
81 125BD57E22171D73008A3575 /* Extentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extentions.swift; sourceTree = "<group>"; };
122 125BD5802217314A008A3575 /* NewsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsVC.swift; sourceTree = "<group>"; };
82 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>"; };
127 1288B5CD221F1158002BE6B1 /* DataStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStorage.swift; sourceTree = "<group>"; };
83 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>"; };
84 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>"; };
85 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>"; };
86+ 1291BE3522218DBF009D3F23 /* LogInCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInCoordinator.swift; sourceTree = "<group>"; };
138− 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TaggerKit.framework; path = Carthage/Build/iOS/TaggerKit.framework; sourceTree = "<group>"; };
139 12D7D132221C321600B35452 /* ChannelListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelListController.swift; sourceTree = "<group>"; };
87 12D7D132221C321600B35452 /* ChannelListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelListController.swift; sourceTree = "<group>"; };
140 12D7D134221C42B700B35452 /* ChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelController.swift; sourceTree = "<group>"; };
88 12D7D134221C42B700B35452 /* ChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelController.swift; sourceTree = "<group>"; };
141 12D7D136221D78E800B35452 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
89 12D7D136221D78E800B35452 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
@@ -151,24 +99,18 @@
151 12E36DA2221424ED006FCDD7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
99 12E36DA2221424ED006FCDD7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
152 12E36DA5221424ED006FCDD7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
100 12E36DA5221424ED006FCDD7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
153 12E36DA7221424ED006FCDD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
101 12E36DA7221424ED006FCDD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
102+ 12E36DAE22143D40006FCDD7 /* Cartography.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cartography.framework; path = Carthage/Build/iOS/Cartography.framework; sourceTree = "<group>"; };
103+ 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MarkdownKit.framework; path = Carthage/Build/iOS/MarkdownKit.framework; sourceTree = "<group>"; };
104+ 12E36DB222143D4E006FCDD7 /* Marklight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Marklight.framework; path = Carthage/Build/iOS/Marklight.framework; sourceTree = "<group>"; };
105+ 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TinyConstraints.framework; path = Carthage/Build/iOS/TinyConstraints.framework; sourceTree = "<group>"; };
154 12E36DB62214400A006FCDD7 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
106 12E36DB62214400A006FCDD7 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
107+ 12E36DB822144016006FCDD7 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
155 12E36DC922144635006FCDD7 /* NewPostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPostViewController.swift; sourceTree = "<group>"; };
108 12E36DC922144635006FCDD7 /* NewPostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPostViewController.swift; sourceTree = "<group>"; };
156 12E36DCB22144725006FCDD7 /* PostViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewCell.swift; sourceTree = "<group>"; };
109 12E36DCB22144725006FCDD7 /* PostViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewCell.swift; sourceTree = "<group>"; };
157 12E36DCD22144756006FCDD7 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
110 12E36DCD22144756006FCDD7 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
158 12E36DD022148122006FCDD7 /* FullPostController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullPostController.swift; sourceTree = "<group>"; };
111 12E36DD022148122006FCDD7 /* FullPostController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullPostController.swift; sourceTree = "<group>"; };
159 12E36DD422156559006FCDD7 /* MyStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyStackView.swift; sourceTree = "<group>"; };
112 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>"; };
113+ 12E36DD622159493006FCDD7 /* TagListView.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TagListView.framework; path = Carthage/Build/iOS/TagListView.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>"; };
172/* End PBXFileReference section */
114/* End PBXFileReference section */
173
115
174/* Begin PBXFrameworksBuildPhase section */
116/* Begin PBXFrameworksBuildPhase section */
@@ -176,17 +118,12 @@
176 isa = PBXFrameworksBuildPhase;
118 isa = PBXFrameworksBuildPhase;
177 buildActionMask = 2147483647;
119 buildActionMask = 2147483647;
178 files = (
120 files = (
179− 12FDAC7C226B5E2900995B4E /* Marklight.framework in Frameworks */,
180− 12FDAC96226B61C400995B4E /* TinyConstraints.framework in Frameworks */,
121+ 12E36DB522143D54006FCDD7 /* TinyConstraints.framework in Frameworks */,
181− 12FDAC91226B5E5400995B4E /* Pulley.framework in Frameworks */,
182− 12FDAC9F226B9E7C00995B4E /* ReactiveCocoa.framework in Frameworks */,
183− 12FDAC88226B5E4800995B4E /* Alamofire.framework in Frameworks */,
122+ 124CC7052221C2BB009DF531 /* Alamofire.framework in Frameworks */,
184− 12FDAC81226B5E2900995B4E /* MarkdownKit.framework in Frameworks */,
123+ 12E36DDB221594B1006FCDD7 /* MarkdownKit.framework in Frameworks */,
185− 12FDAC7D226B5E2900995B4E /* Result.framework in Frameworks */,
124+ 12E36DD8221594A9006FCDD7 /* TagListView.framework in Frameworks */,
186− 12FDAC9B226B652C00995B4E /* ReactiveSwift.framework in Frameworks */,
187− 12FDAC7E226B5E2900995B4E /* Cartography.framework in Frameworks */,
125+ 12E36DAF22143D40006FCDD7 /* Cartography.framework in Frameworks */,
188− 12CE7D6F227B94B10024B6E8 /* TaggerKit.framework in Frameworks */,
189− 12FDAC8B226B5E4E00995B4E /* Hero.framework in Frameworks */,
126+ 12E36DB322143D4E006FCDD7 /* Marklight.framework in Frameworks */,
190 );
127 );
191 runOnlyForDeploymentPostprocessing = 0;
128 runOnlyForDeploymentPostprocessing = 0;
192 };
129 };
@@ -206,68 +143,32 @@
206 path = Profile;
143 path = Profile;
207 sourceTree = "<group>";
144 sourceTree = "<group>";
208 };
145 };
209− 1291BE32222154C3009D3F23 /* Coordinators */ = {
146+ 1291BE32222154C3009D3F23 /* Coordinator tab bar? */ = {
210 isa = PBXGroup;
147 isa = PBXGroup;
211 children = (
148 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 */,
149 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */,
220 );
150 );
221− path = Coordinators;
151+ path = "Coordinator tab bar?";
222 sourceTree = "<group>";
152 sourceTree = "<group>";
223 };
153 };
224 1291BE3722218DC4009D3F23 /* Log In */ = {
154 1291BE3722218DC4009D3F23 /* Log In */ = {
225 isa = PBXGroup;
155 isa = PBXGroup;
226 children = (
156 children = (
227− 125A9A912286100800513E2A /* FacultyTableViewController.swift */,
228− 125A9A8F228609C500513E2A /* InititalsViewCell.swift */,
229− 125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */,
230− 125A9A892285C3DA00513E2A /* CodeViewController.swift */,
231 123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
157 123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
158+ 1291BE3522218DBF009D3F23 /* LogInCoordinator.swift */,
232 );
159 );
233 path = "Log In";
160 path = "Log In";
234 sourceTree = "<group>";
161 sourceTree = "<group>";
235 };
162 };
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− };
257 12E36D8F221424EA006FCDD7 = {
163 12E36D8F221424EA006FCDD7 = {
258 isa = PBXGroup;
164 isa = PBXGroup;
259 children = (
165 children = (
260− 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */,
166+ 124CC7042221C2BA009DF531 /* Alamofire.framework */,
261− 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */,
167+ 12E36DD622159493006FCDD7 /* TagListView.framework */,
262− 12FDAC99226B652400995B4E /* ReactiveSwift.framework */,
263− 12FDAC95226B61C400995B4E /* TinyConstraints.framework */,
168+ 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */,
264− 12FDAC79226B5E2900995B4E /* Alamofire.framework */,
169+ 12E36DB222143D4E006FCDD7 /* Marklight.framework */,
265− 12FDAC77226B5E2900995B4E /* Cartography.framework */,
266− 12FDAC78226B5E2900995B4E /* Hero.framework */,
267− 12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */,
170+ 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */,
268− 12FDAC75226B5E2800995B4E /* Marklight.framework */,
171+ 12E36DAE22143D40006FCDD7 /* Cartography.framework */,
269− 12FDAC7B226B5E2900995B4E /* Pulley.framework */,
270− 12FDAC76226B5E2800995B4E /* Result.framework */,
271 12E36D9A221424EA006FCDD7 /* GDproject */,
172 12E36D9A221424EA006FCDD7 /* GDproject */,
272 12E36D99221424EA006FCDD7 /* Products */,
173 12E36D99221424EA006FCDD7 /* Products */,
273 12E36DDA221594B1006FCDD7 /* Frameworks */,
174 12E36DDA221594B1006FCDD7 /* Frameworks */,
@@ -303,9 +204,9 @@
303 isa = PBXGroup;
204 isa = PBXGroup;
304 children = (
205 children = (
305 124CC7022221C00C009DF531 /* Model.swift */,
206 124CC7022221C00C009DF531 /* Model.swift */,
306− 1293200C2279D7310035C7B3 /* CompletionTree.swift */,
307 12E36DB62214400A006FCDD7 /* Post.swift */,
207 12E36DB62214400A006FCDD7 /* Post.swift */,
308 12D7D136221D78E800B35452 /* Channel.swift */,
208 12D7D136221D78E800B35452 /* Channel.swift */,
209+ 12E36DB822144016006FCDD7 /* User.swift */,
309 );
210 );
310 path = "Simple model";
211 path = "Simple model";
311 sourceTree = "<group>";
212 sourceTree = "<group>";
@@ -323,8 +224,8 @@
323 12E36DCF22145923006FCDD7 /* Controller */ = {
224 12E36DCF22145923006FCDD7 /* Controller */ = {
324 isa = PBXGroup;
225 isa = PBXGroup;
325 children = (
226 children = (
326− 1291BE32222154C3009D3F23 /* Coordinators */,
227+ 1253867C2223DC9F00CC5EA7 /* RepeatingTimer.swift */,
327− 129320052279B4300035C7B3 /* Messages */,
228+ 1291BE32222154C3009D3F23 /* Coordinator tab bar? */,
328 1291BE3722218DC4009D3F23 /* Log In */,
229 1291BE3722218DC4009D3F23 /* Log In */,
329 1288B5CC221F0EFE002BE6B1 /* Profile */,
230 1288B5CC221F0EFE002BE6B1 /* Profile */,
330 12E36DD322156519006FCDD7 /* News and channels */,
231 12E36DD322156519006FCDD7 /* News and channels */,
@@ -335,16 +236,12 @@
335 12E36DD322156519006FCDD7 /* News and channels */ = {
236 12E36DD322156519006FCDD7 /* News and channels */ = {
336 isa = PBXGroup;
237 isa = PBXGroup;
337 children = (
238 children = (
338− 1261BB92227B364C003898CF /* ChannelViewController.swift */,
339− 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */,
340− 1261BB94227B3991003898CF /* AddToChannelVC.swift */,
341 12D7D134221C42B700B35452 /* ChannelController.swift */,
239 12D7D134221C42B700B35452 /* ChannelController.swift */,
342− 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */,
343 12D7D132221C321600B35452 /* ChannelListController.swift */,
240 12D7D132221C321600B35452 /* ChannelListController.swift */,
344− 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */,
345 12E36DC922144635006FCDD7 /* NewPostViewController.swift */,
241 12E36DC922144635006FCDD7 /* NewPostViewController.swift */,
346 12E36DD022148122006FCDD7 /* FullPostController.swift */,
242 12E36DD022148122006FCDD7 /* FullPostController.swift */,
347 12E36D9D221424EA006FCDD7 /* NewsController.swift */,
243 12E36D9D221424EA006FCDD7 /* NewsController.swift */,
244+ 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */,
348 125BD5802217314A008A3575 /* NewsVC.swift */,
245 125BD5802217314A008A3575 /* NewsVC.swift */,
349 12E36DCB22144725006FCDD7 /* PostViewCell.swift */,
246 12E36DCB22144725006FCDD7 /* PostViewCell.swift */,
350 );
247 );
@@ -368,7 +265,7 @@
368 12E36D94221424EA006FCDD7 /* Sources */,
265 12E36D94221424EA006FCDD7 /* Sources */,
369 12E36D95221424EA006FCDD7 /* Frameworks */,
266 12E36D95221424EA006FCDD7 /* Frameworks */,
370 12E36D96221424EA006FCDD7 /* Resources */,
267 12E36D96221424EA006FCDD7 /* Resources */,
371− 12FDAC85226B5E3700995B4E /* Embed Frameworks */,
268+ 12E36DBE221441D5006FCDD7 /* Embed Frameworks */,
372 );
269 );
373 buildRules = (
270 buildRules = (
374 );
271 );
@@ -391,11 +288,6 @@
391 TargetAttributes = {
288 TargetAttributes = {
392 12E36D97221424EA006FCDD7 = {
289 12E36D97221424EA006FCDD7 = {
393 CreatedOnToolsVersion = 10.1;
290 CreatedOnToolsVersion = 10.1;
394− SystemCapabilities = {
395− com.apple.Keychain = {
396− enabled = 0;
397− };
398− };
399 };
291 };
400 };
292 };
401 };
293 };
@@ -435,49 +327,30 @@
435 isa = PBXSourcesBuildPhase;
327 isa = PBXSourcesBuildPhase;
436 buildActionMask = 2147483647;
328 buildActionMask = 2147483647;
437 files = (
329 files = (
438− 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */,
439 124CC7032221C00C009DF531 /* Model.swift in Sources */,
330 124CC7032221C00C009DF531 /* Model.swift in Sources */,
440− 125A9A90228609C500513E2A /* InititalsViewCell.swift in Sources */,
441− 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */,
442− 12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */,
443 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
331 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
444 12D7D137221D78E800B35452 /* Channel.swift in Sources */,
332 12D7D137221D78E800B35452 /* Channel.swift in Sources */,
445− 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */,
333+ 1291BE3622218DBF009D3F23 /* LogInCoordinator.swift in Sources */,
334+ 12E36DB922144016006FCDD7 /* User.swift in Sources */,
446 125BD5812217314A008A3575 /* NewsVC.swift in Sources */,
335 125BD5812217314A008A3575 /* NewsVC.swift in Sources */,
447 12E36DB72214400A006FCDD7 /* Post.swift in Sources */,
336 12E36DB72214400A006FCDD7 /* Post.swift in Sources */,
448 12DB7FDF221877160096878E /* InviteViewController.swift in Sources */,
337 12DB7FDF221877160096878E /* InviteViewController.swift in Sources */,
449− 121A8972226B1EAC005EE599 /* TagsSuggestionController.swift in Sources */,
450− 1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */,
451 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */,
338 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */,
452− 1261BB9E227B793D003898CF /* ChatInfoViewController.swift in Sources */,
453 12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */,
339 12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */,
454− 1298810B227F13840032ACA3 /* DialogCell.swift in Sources */,
455− 125A9A922286100800513E2A /* FacultyTableViewController.swift in Sources */,
456− 125A9A8E2286068A00513E2A /* RegisterTableViewController.swift in Sources */,
457− 123589FD22899339002F8028 /* MessageViewCell.swift in Sources */,
458 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */,
340 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */,
459 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */,
341 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */,
460 125BD57F22171D73008A3575 /* Extentions.swift in Sources */,
342 125BD57F22171D73008A3575 /* Extentions.swift in Sources */,
461 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */,
343 12D7D133221C321600B35452 /* ChannelListController.swift in Sources */,
462− 125A9A8A2285C3DA00513E2A /* CodeViewController.swift in Sources */,
463 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */,
344 1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */,
464− 129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */,
465− 12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */,
466 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */,
345 1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */,
467 12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */,
346 12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */,
468− 129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */,
469− 12758257227F1401001F291F /* DialogViewController.swift in Sources */,
470 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */,
347 1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */,
471− 12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */,
472− 12F3D6B22241097B00A69214 /* ProfileCoordinator.swift in Sources */,
473 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */,
348 125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */,
474− 1261BB95227B3991003898CF /* AddToChannelVC.swift in Sources */,
349+ 1253867D2223DC9F00CC5EA7 /* RepeatingTimer.swift in Sources */,
475 12DB7FDB2218590C0096878E /* InfoCell.swift in Sources */,
350 12DB7FDB2218590C0096878E /* InfoCell.swift in Sources */,
476 12DB7FD922181E660096878E /* BasicInfoCell.swift in Sources */,
351 12DB7FD922181E660096878E /* BasicInfoCell.swift in Sources */,
477− 1261BB93227B364C003898CF /* ChannelViewController.swift in Sources */,
478 12D7D135221C42B700B35452 /* ChannelController.swift in Sources */,
352 12D7D135221C42B700B35452 /* ChannelController.swift in Sources */,
479 12E36D9C221424EA006FCDD7 /* AppDelegate.swift in Sources */,
353 12E36D9C221424EA006FCDD7 /* AppDelegate.swift in Sources */,
480− 12BA4B9D224101E700DF93D7 /* BaseCoordinator.swift in Sources */,
481 12DB7FD722181CD20096878E /* BasicInfoController.swift in Sources */,
354 12DB7FD722181CD20096878E /* BasicInfoController.swift in Sources */,
482 12E36DCE22144756006FCDD7 /* Constants.swift in Sources */,
355 12E36DCE22144756006FCDD7 /* Constants.swift in Sources */,
483 12DB7FDD221872F80096878E /* SettingsViewController.swift in Sources */,
356 12DB7FDD221872F80096878E /* SettingsViewController.swift in Sources */,
@@ -627,7 +500,6 @@
627 isa = XCBuildConfiguration;
500 isa = XCBuildConfiguration;
628 buildSettings = {
501 buildSettings = {
629 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
502 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
630− CODE_SIGN_IDENTITY = "iPhone Developer";
631 CODE_SIGN_STYLE = Automatic;
503 CODE_SIGN_STYLE = Automatic;
632 DEVELOPMENT_TEAM = 9Z6LFGKA9G;
504 DEVELOPMENT_TEAM = 9Z6LFGKA9G;
633 FRAMEWORK_SEARCH_PATHS = (
505 FRAMEWORK_SEARCH_PATHS = (
@@ -639,10 +511,9 @@
639 "$(inherited)",
511 "$(inherited)",
640 "@executable_path/Frameworks",
512 "@executable_path/Frameworks",
641 );
513 );
642− PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject.sos;
514+ PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject;
643 PRODUCT_NAME = "$(TARGET_NAME)";
515 PRODUCT_NAME = "$(TARGET_NAME)";
644− PROVISIONING_PROFILE_SPECIFIER = "";
645− SWIFT_VERSION = 5.0;
516+ SWIFT_VERSION = 4.2;
646 TARGETED_DEVICE_FAMILY = "1,2";
517 TARGETED_DEVICE_FAMILY = "1,2";
647 };
518 };
648 name = Debug;
519 name = Debug;
@@ -651,7 +522,6 @@
651 isa = XCBuildConfiguration;
522 isa = XCBuildConfiguration;
652 buildSettings = {
523 buildSettings = {
653 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
524 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
654− CODE_SIGN_IDENTITY = "iPhone Developer";
655 CODE_SIGN_STYLE = Automatic;
525 CODE_SIGN_STYLE = Automatic;
656 DEVELOPMENT_TEAM = 9Z6LFGKA9G;
526 DEVELOPMENT_TEAM = 9Z6LFGKA9G;
657 FRAMEWORK_SEARCH_PATHS = (
527 FRAMEWORK_SEARCH_PATHS = (
@@ -663,10 +533,9 @@
663 "$(inherited)",
533 "$(inherited)",
664 "@executable_path/Frameworks",
534 "@executable_path/Frameworks",
665 );
535 );
666− PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject.sos;
536+ PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject;
667 PRODUCT_NAME = "$(TARGET_NAME)";
537 PRODUCT_NAME = "$(TARGET_NAME)";
668− PROVISIONING_PROFILE_SPECIFIER = "";
669− SWIFT_VERSION = 5.0;
538+ SWIFT_VERSION = 4.2;
670 TARGETED_DEVICE_FAMILY = "1,2";
539 TARGETED_DEVICE_FAMILY = "1,2";
671 };
540 };
672 name = Release;
541 name = Release;
GDproject/Base.lproj/Main.storyboard+93−702
@@ -1,30 +1,16 @@
1<?xml version="1.0" encoding="UTF-8"?>
1<?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="609-2j-gc9">
3 <device id="retina4_7" orientation="portrait">
3 <device id="retina4_7" orientation="portrait">
4 <adaptation id="fullscreen"/>
4 <adaptation id="fullscreen"/>
5 </device>
5 </device>
6 <dependencies>
6 <dependencies>
7 <deployment identifier="iOS"/>
7 <deployment identifier="iOS"/>
8− <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
8+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
9 <capability name="Safe area layout guides" minToolsVersion="9.0"/>
9 <capability name="Safe area layout guides" minToolsVersion="9.0"/>
10 <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
10 <capability name="Stack View standard spacing" minToolsVersion="9.0"/>
11 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
11 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
12 </dependencies>
12 </dependencies>
13 <scenes>
13 <scenes>
14− <!--Chats-->
15− <scene sceneID="bZ2-fw-XBE">
16− <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"/>
25− </objects>
26− <point key="canvasLocation" x="1089" y="481"/>
27− </scene>
28 <!--Profile View Controller-->
14 <!--Profile View Controller-->
29 <scene sceneID="rQ6-TM-V7T">
15 <scene sceneID="rQ6-TM-V7T">
30 <objects>
16 <objects>
@@ -34,7 +20,7 @@
34 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
20 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
35 <subviews>
21 <subviews>
36 <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">
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="cay-ea-rTl">
37− <rect key="frame" x="0.0" y="20" width="375" height="647"/>
23+ <rect key="frame" x="0.0" y="116" width="375" height="502"/>
38 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
24 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
39 <view key="tableHeaderView" contentMode="scaleToFill" id="kFZ-3c-OFY">
25 <view key="tableHeaderView" contentMode="scaleToFill" id="kFZ-3c-OFY">
40 <rect key="frame" x="0.0" y="0.0" width="375" height="199"/>
26 <rect key="frame" x="0.0" y="0.0" width="375" height="199"/>
@@ -90,9 +76,6 @@
90 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yir-N6-Q6f">
76 <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"/>
77 <rect key="frame" x="246" y="0.0" width="97" height="30"/>
92 <state key="normal" title="New message"/>
78 <state key="normal" title="New message"/>
93− <connections>
94− <action selector="sendMessage:" destination="R4D-Ao-uvG" eventType="touchUpInside" id="tQc-5f-SU3"/>
95− </connections>
96 </button>
79 </button>
97 </subviews>
80 </subviews>
98 </stackView>
81 </stackView>
@@ -148,7 +131,7 @@
148 </viewController>
131 </viewController>
149 <placeholder placeholderIdentifier="IBFirstResponder" id="sap-zV-B7l" userLabel="First Responder" sceneMemberID="firstResponder"/>
132 <placeholder placeholderIdentifier="IBFirstResponder" id="sap-zV-B7l" userLabel="First Responder" sceneMemberID="firstResponder"/>
150 </objects>
133 </objects>
151− <point key="canvasLocation" x="1884" y="1216"/>
134+ <point key="canvasLocation" x="2013.5999999999999" y="957.57121439280365"/>
152 </scene>
135 </scene>
153 <!--Settings View Controller-->
136 <!--Settings View Controller-->
154 <scene sceneID="WVn-Qy-9tO">
137 <scene sceneID="WVn-Qy-9tO">
@@ -185,7 +168,7 @@
185 </tableViewController>
168 </tableViewController>
186 <placeholder placeholderIdentifier="IBFirstResponder" id="xdg-ZK-4Jv" userLabel="First Responder" sceneMemberID="firstResponder"/>
169 <placeholder placeholderIdentifier="IBFirstResponder" id="xdg-ZK-4Jv" userLabel="First Responder" sceneMemberID="firstResponder"/>
187 </objects>
170 </objects>
188− <point key="canvasLocation" x="1980" y="1979"/>
171+ <point key="canvasLocation" x="1986" y="1756"/>
189 </scene>
172 </scene>
190 <!--Invite View Controller-->
173 <!--Invite View Controller-->
191 <scene sceneID="DcO-6Y-Iko">
174 <scene sceneID="DcO-6Y-Iko">
@@ -229,295 +212,7 @@
229 </viewController>
212 </viewController>
230 <placeholder placeholderIdentifier="IBFirstResponder" id="t8a-Sv-mbh" userLabel="First Responder" sceneMemberID="firstResponder"/>
213 <placeholder placeholderIdentifier="IBFirstResponder" id="t8a-Sv-mbh" userLabel="First Responder" sceneMemberID="firstResponder"/>
231 </objects>
214 </objects>
232− <point key="canvasLocation" x="2799" y="1979"/>
215+ <point key="canvasLocation" x="2803" y="1756"/>
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"/>
521 </scene>
216 </scene>
522 <!--Channel List Controller-->
217 <!--Channel List Controller-->
523 <scene sceneID="4eb-Jz-gcx">
218 <scene sceneID="4eb-Jz-gcx">
@@ -615,7 +310,7 @@
615 </viewController>
310 </viewController>
616 <placeholder placeholderIdentifier="IBFirstResponder" id="fzv-8a-15V" userLabel="First Responder" sceneMemberID="firstResponder"/>
311 <placeholder placeholderIdentifier="IBFirstResponder" id="fzv-8a-15V" userLabel="First Responder" sceneMemberID="firstResponder"/>
617 </objects>
312 </objects>
618− <point key="canvasLocation" x="3577" y="-598"/>
313+ <point key="canvasLocation" x="3560.8000000000002" y="-597.75112443778119"/>
619 </scene>
314 </scene>
620 <!--New Post View Controller-->
315 <!--New Post View Controller-->
621 <scene sceneID="TVK-xu-UdJ">
316 <scene sceneID="TVK-xu-UdJ">
@@ -625,36 +320,23 @@
625 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
320 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
626 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
321 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
627 <subviews>
322 <subviews>
628− <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aRT-Du-PVE">
323+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sSz-uJ-A7n">
629− <rect key="frame" x="0.0" y="62" width="375" height="605"/>
324+ <rect key="frame" x="0.0" y="20" width="375" height="647"/>
630 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
325 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
631 </view>
326 </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>
642 </subviews>
327 </subviews>
643 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
328 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
644 <constraints>
329 <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"/>
330+ <constraint firstItem="sSz-uJ-A7n" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="2J7-Bi-PzG"/>
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"/>
331+ <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="sSz-uJ-A7n" secondAttribute="trailing" id="HrU-bs-qsE"/>
650− <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="bHv-9b-9uA" secondAttribute="trailing" constant="16" id="Ufp-mQ-Xeo"/>
332+ <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="sSz-uJ-A7n" secondAttribute="bottom" id="oZ7-xQ-9Cb"/>
651− <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="aRT-Du-PVE" secondAttribute="bottom" id="x3f-eb-ACt"/>
333+ <constraint firstItem="sSz-uJ-A7n" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" id="zuN-mZ-hgU"/>
652 </constraints>
334 </constraints>
653 <viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
335 <viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
654 </view>
336 </view>
655 <connections>
337 <connections>
656− <outlet property="bottomTextViewConstraint" destination="x3f-eb-ACt" id="ktT-im-InH"/>
338+ <outlet property="bottomTextViewConstraint" destination="oZ7-xQ-9Cb" id="6In-71-0TX"/>
657− <outlet property="view1" destination="aRT-Du-PVE" id="DXD-HR-NcE"/>
339+ <outlet property="view1" destination="sSz-uJ-A7n" id="5nX-oT-kUi"/>
658 </connections>
340 </connections>
659 </viewController>
341 </viewController>
660 <placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
342 <placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -679,352 +361,54 @@
679 </objects>
361 </objects>
680 <point key="canvasLocation" x="3444" y="129.98500749625188"/>
362 <point key="canvasLocation" x="3444" y="129.98500749625188"/>
681 </scene>
363 </scene>
682− <!--Taggs Selection View Controller-->
364+ <!--Log In View Controller-->
683− <scene sceneID="74G-Lc-cqT">
365+ <scene sceneID="Pkd-pB-bQs">
684 <objects>
366 <objects>
685− <viewController storyboardIdentifier="TaggsSelectionViewController" id="rQl-ri-9O8" customClass="TaggsSelectionViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
367+ <viewController storyboardIdentifier="LogInController" id="ZCz-70-hDh" customClass="LogInViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
686− <view key="view" contentMode="scaleToFill" id="k3T-8B-NVf">
368+ <view key="view" contentMode="scaleToFill" id="1q2-4g-KZs">
687 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
369 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
688 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
370 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
689 <subviews>
371 <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">
372+ <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="UwC-m5-jA5">
697− <rect key="frame" x="16" y="306" width="343" height="184"/>
373+ <rect key="frame" x="16" y="100" width="343" height="83"/>
698− <constraints>
374+ <subviews>
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">
375+ <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">
703− <rect key="frame" x="16" y="28" width="73" height="21"/>
376+ <rect key="frame" x="0.0" y="0.0" width="343" height="41"/>
704− <constraints>
705− <constraint firstAttribute="height" constant="21" id="KZW-ld-K8d"/>
706− </constraints>
707− <fontDescription key="fontDescription" type="system" pointSize="17"/>
377+ <fontDescription key="fontDescription" type="boldSystem" pointSize="34"/>
708− <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
378+ <nil key="textColor"/>
709− <nil key="highlightedColor"/>
379+ <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>
380+ </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">
381+ <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Mail" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="mFP-WG-jY5">
730− <rect key="frame" x="16" y="57" width="343" height="30"/>
382+ <rect key="frame" x="0.0" y="53" width="343" height="30"/>
731− <constraints>
383+ <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
732− <constraint firstAttribute="height" constant="30" id="dBr-rd-Cg8"/>
733− </constraints>
734− <nil key="textColor"/>
384+ <nil key="textColor"/>
735− <fontDescription key="fontDescription" type="system" pointSize="14"/>
385+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
736− <textInputTraits key="textInputTraits"/>
386+ <textInputTraits key="textInputTraits"/>
737− </textField>
387+ </textField>
388+ </subviews>
389+ </stackView>
390+ <activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="K3b-gv-JPp">
391+ <rect key="frame" x="177.5" y="333.5" width="20" height="20"/>
392+ </activityIndicatorView>
738 </subviews>
393 </subviews>
739 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
394 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
740 <constraints>
395 <constraints>
741− <constraint firstItem="hvS-Ix-A23" firstAttribute="top" secondItem="BgX-NT-7NG" secondAttribute="bottom" constant="19" id="17U-ae-Gxa"/>
396+ <constraint firstItem="UwC-m5-jA5" firstAttribute="leading" secondItem="LOR-Yw-0FU" secondAttribute="leading" constant="16" id="M6z-nU-H40"/>
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"/>
397+ <constraint firstItem="K3b-gv-JPp" firstAttribute="centerY" secondItem="LOR-Yw-0FU" secondAttribute="centerY" id="eOp-yQ-n28"/>
755− <constraint firstItem="lEu-rZ-H6U" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qCJ-rc-qBq"/>
398+ <constraint firstItem="K3b-gv-JPp" firstAttribute="centerX" secondItem="LOR-Yw-0FU" secondAttribute="centerX" id="gdW-VU-pE8"/>
756− <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lEu-rZ-H6U" secondAttribute="trailing" constant="16" id="vaR-Zr-5nI"/>
399+ <constraint firstItem="LOR-Yw-0FU" firstAttribute="trailing" secondItem="UwC-m5-jA5" secondAttribute="trailing" constant="16" id="jST-rr-MMX"/>
757− <constraint firstItem="hvS-Ix-A23" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="vcb-xj-bM8"/>
400+ <constraint firstItem="UwC-m5-jA5" firstAttribute="top" secondItem="LOR-Yw-0FU" secondAttribute="top" constant="80" id="rvy-Ii-bwS"/>
758− <constraint firstItem="BgX-NT-7NG" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="xOL-J4-JIV"/>
759 </constraints>
401 </constraints>
760− <viewLayoutGuide key="safeArea" id="Oc2-oW-bST"/>
402+ <viewLayoutGuide key="safeArea" id="LOR-Yw-0FU"/>
761 </view>
403 </view>
762 <connections>
404 <connections>
763− <outlet property="addTagsTextField" destination="BgX-NT-7NG" id="3vt-U9-NYI"/>
405+ <outlet property="indicatorView" destination="K3b-gv-JPp" id="mSR-QU-VZQ"/>
764− <outlet property="searchContainerView" destination="yeR-J3-ysT" id="SzT-fM-A6H"/>
765− <outlet property="testContainer" destination="lEu-rZ-H6U" id="DTe-9O-VAi"/>
406+ <outlet property="mailTextField" destination="mFP-WG-jY5" id="7SN-qe-DDm"/>
766 </connections>
407 </connections>
767 </viewController>
408 </viewController>
768− <placeholder placeholderIdentifier="IBFirstResponder" id="eoH-1e-A6A" userLabel="First Responder" sceneMemberID="firstResponder"/>
409+ <placeholder placeholderIdentifier="IBFirstResponder" id="6e8-oo-bbc" 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"/>
874− </objects>
875− <point key="canvasLocation" x="3614" y="938"/>
876− </scene>
877− <!--Chat Info View Controller-->
878− <scene sceneID="1br-Xg-fR9">
879− <objects>
880− <tableViewController storyboardIdentifier="ChatInfoViewController" id="Rfd-Hp-Qqv" customClass="ChatInfoViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
881− <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="Rvg-ok-cnE">
882− <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
883− <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
884− <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
885− <prototypes>
886− <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" textLabel="EdJ-of-2FG" style="IBUITableViewCellStyleDefault" id="hl5-Uc-R53">
887− <rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
888− <autoresizingMask key="autoresizingMask"/>
889− <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hl5-Uc-R53" id="Oy5-4e-dPI">
890− <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
891− <autoresizingMask key="autoresizingMask"/>
892− <subviews>
893− <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="EdJ-of-2FG">
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>
410 </objects>
1027− <point key="canvasLocation" x="6548" y="448"/>
411+ <point key="canvasLocation" x="-466" y="-821"/>
1028 </scene>
412 </scene>
1029 <!--Posts-->
413 <!--Posts-->
1030 <scene sceneID="RSd-UJ-34B">
414 <scene sceneID="RSd-UJ-34B">
@@ -1037,10 +421,33 @@
1037 <autoresizingMask key="autoresizingMask"/>
421 <autoresizingMask key="autoresizingMask"/>
1038 </navigationBar>
422 </navigationBar>
1039 <nil name="viewControllers"/>
423 <nil name="viewControllers"/>
424+ <connections>
425+ <segue destination="Nqc-TI-ueQ" kind="relationship" relationship="rootViewController" id="2BZ-i4-uIE"/>
426+ </connections>
1040 </navigationController>
427 </navigationController>
1041 <placeholder placeholderIdentifier="IBFirstResponder" id="POV-5T-jeQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
428 <placeholder placeholderIdentifier="IBFirstResponder" id="POV-5T-jeQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
1042 </objects>
429 </objects>
1043− <point key="canvasLocation" x="1089" y="-306"/>
430+ <point key="canvasLocation" x="1088.8" y="132.68365817091455"/>
431+ </scene>
432+ <!--News Controller-->
433+ <scene sceneID="eR7-97-LRL">
434+ <objects>
435+ <tableViewController storyboardIdentifier="NewsController" id="Nqc-TI-ueQ" customClass="NewsController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
436+ <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="hwA-SE-xpS">
437+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
438+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
439+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
440+ <color key="sectionIndexBackgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
441+ <connections>
442+ <outlet property="dataSource" destination="Nqc-TI-ueQ" id="bu5-tQ-7lb"/>
443+ <outlet property="delegate" destination="Nqc-TI-ueQ" id="kTM-Be-8qb"/>
444+ </connections>
445+ </tableView>
446+ <navigationItem key="navigationItem" largeTitleDisplayMode="always" id="b8E-6f-hLM"/>
447+ </tableViewController>
448+ <placeholder placeholderIdentifier="IBFirstResponder" id="c9d-Kh-itI" userLabel="First Responder" sceneMemberID="firstResponder"/>
449+ </objects>
450+ <point key="canvasLocation" x="1880" y="136"/>
1044 </scene>
451 </scene>
1045 <!--Profile-->
452 <!--Profile-->
1046 <scene sceneID="dJj-Hp-Wa9">
453 <scene sceneID="dJj-Hp-Wa9">
@@ -1053,15 +460,31 @@
1053 <autoresizingMask key="autoresizingMask"/>
460 <autoresizingMask key="autoresizingMask"/>
1054 </navigationBar>
461 </navigationBar>
1055 <nil name="viewControllers"/>
462 <nil name="viewControllers"/>
463+ <connections>
464+ <segue destination="R4D-Ao-uvG" kind="relationship" relationship="rootViewController" id="aF6-zK-hCB"/>
465+ </connections>
1056 </navigationController>
466 </navigationController>
1057 <placeholder placeholderIdentifier="IBFirstResponder" id="Fvm-qf-2Ve" userLabel="First Responder" sceneMemberID="firstResponder"/>
467 <placeholder placeholderIdentifier="IBFirstResponder" id="Fvm-qf-2Ve" userLabel="First Responder" sceneMemberID="firstResponder"/>
1058 </objects>
468 </objects>
1059− <point key="canvasLocation" x="1015" y="1216"/>
469+ <point key="canvasLocation" x="1089" y="958"/>
470+ </scene>
471+ <!--Navigation Controller-->
472+ <scene sceneID="r0M-xH-UwU">
473+ <objects>
474+ <navigationController storyboardIdentifier="root" id="609-2j-gc9" sceneMemberID="viewController">
475+ <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Ah8-NU-AsD">
476+ <rect key="frame" x="0.0" y="20" width="375" height="44"/>
477+ <autoresizingMask key="autoresizingMask"/>
478+ </navigationBar>
479+ </navigationController>
480+ <placeholder placeholderIdentifier="IBFirstResponder" id="Raj-78-jlT" userLabel="First Responder" sceneMemberID="firstResponder"/>
481+ </objects>
482+ <point key="canvasLocation" x="-2242" y="68"/>
1060 </scene>
483 </scene>
1061− <!--Tabbar Controller-->
484+ <!--Tab Bar Controller-->
1062 <scene sceneID="HCR-WO-p7g">
485 <scene sceneID="HCR-WO-p7g">
1063 <objects>
486 <objects>
1064− <tabBarController storyboardIdentifier="TabbarController" automaticallyAdjustsScrollViewInsets="NO" id="IeP-4W-8LT" customClass="TabbarController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
487+ <tabBarController storyboardIdentifier="TabBar" automaticallyAdjustsScrollViewInsets="NO" id="IeP-4W-8LT" sceneMemberID="viewController">
1065 <toolbarItems/>
488 <toolbarItems/>
1066 <tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="3pl-mU-U30">
489 <tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="3pl-mU-U30">
1067 <rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
490 <rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
@@ -1070,7 +493,6 @@
1070 </tabBar>
493 </tabBar>
1071 <connections>
494 <connections>
1072 <segue destination="NuV-ZG-ld2" kind="relationship" relationship="viewControllers" id="XuX-8s-fZU"/>
495 <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"/>
1074 <segue destination="tae-5q-wvT" kind="relationship" relationship="viewControllers" id="wCJ-4N-lfC"/>
496 <segue destination="tae-5q-wvT" kind="relationship" relationship="viewControllers" id="wCJ-4N-lfC"/>
1075 </connections>
497 </connections>
1076 </tabBarController>
498 </tabBarController>
@@ -1078,40 +500,9 @@
1078 </objects>
500 </objects>
1079 <point key="canvasLocation" x="-466" y="641"/>
501 <point key="canvasLocation" x="-466" y="641"/>
1080 </scene>
502 </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>
1111 </scenes>
503 </scenes>
1112 <resources>
504 <resources>
1113 <image name="1" width="30" height="30"/>
505 <image name="1" width="30" height="30"/>
1114 <image name="5" width="30" height="30"/>
506 <image name="5" width="30" height="30"/>
1115− <image name="chat" width="30" height="30"/>
1116 </resources>
507 </resources>
1117</document>
508</document>
GDproject/Constants.swift−25
@@ -6,7 +6,6 @@
6// Copyright © 2019 drHSE. All rights reserved.
6// Copyright © 2019 drHSE. All rights reserved.
7//
7//
8
8
9−import UIKit
10/// constant for cell in posts NewsController.swift
9/// constant for cell in posts NewsController.swift
11let postCellId = "PostCell"
10let postCellId = "PostCell"
12
11
@@ -43,29 +42,5 @@ let newsController = "NewsController"
43/// constant for switching to view controller for log in app
42/// constant for switching to view controller for log in app
44let logInController = "LogInController"
43let logInController = "LogInController"
45
44
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
45
54let profileViewController = "ProfileViewController"
46let 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+48−93
@@ -25,16 +25,14 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
25 var channel: Model.Channels?
25 var channel: Model.Channels?
26 var myProtocol: DataDelegate?
26 var myProtocol: DataDelegate?
27
27
28− var fullTags: [String] = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
29−
30− var dataSourcePeople: [Model.Users] = []
28+ var dataSourcePeople: [Int] = []
31−
32 var dataSourceTags: [String] = []
29 var dataSourceTags: [String] = []
33
30
34 var activeDataSource: ActiveTable = .people
31 var activeDataSource: ActiveTable = .people
35
32
36− // func to show preview of the current channel
33+ var fullPeople: [Int] = [5051,69]
37− var onShowingPreview: ((Model.Channels)->())?
34+
35+ var fullTags: [String] = ["# happy", "# sad", "# meme", "# shershakov", "# pupsik"]
38
36
39 @IBOutlet weak var viewww: UIView!
37 @IBOutlet weak var viewww: UIView!
40
38
@@ -43,53 +41,8 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
43 override func viewDidLoad() {
41 override func viewDidLoad() {
44 super.viewDidLoad()
42 super.viewDidLoad()
45
43
44+ dataSourcePeople = channel!.people
46 dataSourceTags = channel!.tags
45 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
46
94 tableView.delegate = self
47 tableView.delegate = self
95 tableView.dataSource = self
48 tableView.dataSource = self
@@ -105,12 +58,13 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
105 textField.addTarget(self, action: #selector(changedText(_:)), for: .editingChanged)
58 textField.addTarget(self, action: #selector(changedText(_:)), for: .editingChanged)
106 }
59 }
107
60
108−
61+ override func viewWillDisappear(_ animated: Bool) {
109−
62+ Model.createChannel(with: channel!)
63+ }
110 @objc func changedText(_ textField: UITextField){
64 @objc func changedText(_ textField: UITextField){
111 navigationItem.title = textField.text
65 navigationItem.title = textField.text
112 channel?.name = textField.text!
66 channel?.name = textField.text!
113− // myProtocol?.passData(for: index!, channel: channel!)
67+ myProtocol?.passData(for: index!, channel: channel!)
114 }
68 }
115
69
116 func numberOfSections(in tableView: UITableView) -> Int {
70 func numberOfSections(in tableView: UITableView) -> Int {
@@ -127,12 +81,14 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
127 }
81 }
128
82
129 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
83 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
84+ if searchBar.isFirstResponder {
130− if searchBar.isFirstResponder, let cell = tableView.cellForRow(at: indexPath)
85+ if let cell = tableView.cellForRow(at: indexPath)
131− {
86+ {
87+
132 if cell.accessoryType == .none{
88 if cell.accessoryType == .none{
133 switch searchBar.selectedScopeButtonIndex{
89 switch searchBar.selectedScopeButtonIndex{
134 case 0:
90 case 0:
135− channel?.people.append(dataSourcePeople[indexPath.row].id)
91+ channel?.people.append(dataSourcePeople[indexPath.row])
136 print("people = \(channel!.people)")
92 print("people = \(channel!.people)")
137 case 1:
93 case 1:
138 channel?.tags.append(dataSourceTags[indexPath.row])
94 channel?.tags.append(dataSourceTags[indexPath.row])
@@ -140,33 +96,27 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
140 default:
96 default:
141 break
97 break
142 }
98 }
99+
143 cell.accessoryType = .checkmark
100 cell.accessoryType = .checkmark
144 } else {
101 } else {
145 cell.accessoryType = .none
102 cell.accessoryType = .none
146
103
147 switch searchBar.selectedScopeButtonIndex{
104 switch searchBar.selectedScopeButtonIndex{
148 case 0:
105 case 0:
149− let filtered = channel!.people.filter{ $0 != Model.Channels.fullPeople[indexPath.row].id }
106+ channel?.people = channel!.people.filter{ $0 == fullPeople[indexPath.row] }
150− channel?.people = filtered
107+ // TODO: dataPass
151 case 1:
108 case 1:
152− let filtered = channel!.tags.filter{
109+ channel?.tags = channel!.tags.filter({ (s) -> Bool in
153− !fullTags[indexPath.row].contains($0)
110+ !fullTags[indexPath.row].contains(s)
154− }
111+ })
155− channel?.tags = filtered
112+ // TODO: dataPass
156 default:
113 default:
157 break
114 break
158 }
115 }
159 }
116 }
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)
168 }
117 }
169−
118+ } else
119+ {
170 tableView.beginUpdates()
120 tableView.beginUpdates()
171 switch activeDataSource{
121 switch activeDataSource{
172 case .people:
122 case .people:
@@ -174,20 +124,29 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
174 case .tags:
124 case .tags:
175 dataSourceTags.remove(at: indexPath.row)
125 dataSourceTags.remove(at: indexPath.row)
176 }
126 }
127+ switch searchBar.selectedScopeButtonIndex{
128+ case 0:
129+ channel?.people.remove(at: indexPath.row)
130+ // TODO: dataPass
131+ case 1:
132+ channel?.tags.remove(at: indexPath.row)
133+ // TODO: dataPass
134+ default:
135+ break
136+ }
177 tableView.deleteRows(at: [indexPath], with: .none)
137 tableView.deleteRows(at: [indexPath], with: .none)
178 tableView.endUpdates()
138 tableView.endUpdates()
179 }
139 }
180 }
140 }
181
141
182− func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
142+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
183− {
184 let cell = tableView.dequeueReusableCell(withIdentifier: itemCellId, for: indexPath)
143 let cell = tableView.dequeueReusableCell(withIdentifier: itemCellId, for: indexPath)
185
144
186− cell.textLabel?.text = activeDataSource == .people ? "\(dataSourcePeople[indexPath.row].firstName) \(dataSourcePeople[indexPath.row].middleName) \(dataSourcePeople[indexPath.row].lastName)" : dataSourceTags[indexPath.row]
145+ cell.textLabel?.text = activeDataSource == .people ? String(dataSourcePeople[indexPath.row]) : dataSourceTags[indexPath.row]
187 cell.selectionStyle = .none
146 cell.selectionStyle = .none
188
147
189 if activeDataSource == .tags && channel!.tags.contains(dataSourceTags[indexPath.row]) ||
148 if activeDataSource == .tags && channel!.tags.contains(dataSourceTags[indexPath.row]) ||
190− activeDataSource == .people && channel!.people.contains(dataSourcePeople[indexPath.row].id)
149+ activeDataSource == .people && channel!.people.contains(dataSourcePeople[indexPath.row])
191 {
150 {
192 cell.accessoryType = .checkmark
151 cell.accessoryType = .checkmark
193 } else {
152 } else {
@@ -231,9 +190,9 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
231
190
232 func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
191 func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
233 if searchText.isEmpty {
192 if searchText.isEmpty {
234− switch activeDataSource {
193+ switch activeDataSource{
235 case .people:
194 case .people:
236− dataSourcePeople = Model.Channels.fullPeople
195+ dataSourcePeople = fullPeople
237 case .tags:
196 case .tags:
238 dataSourceTags = fullTags
197 dataSourceTags = fullTags
239 }
198 }
@@ -246,13 +205,12 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
246 func filterTableView(ind: Int, text: String){
205 func filterTableView(ind: Int, text: String){
247 switch ind {
206 switch ind {
248 case 0:
207 case 0:
249− dataSourcePeople = Model.Channels.fullPeople.filter {
208+ dataSourcePeople = fullPeople.filter { if let numb = Int(text) { return $0 == numb } else {return false}}
250− let fullName = "\($0.firstName) \($0.middleName) \($0.lastName)"
251− return fullName.lowercased().contains(text.lowercased())
252− }
253 tableView.reloadData()
209 tableView.reloadData()
254 case 1:
210 case 1:
255− dataSourceTags = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: text)
211+ dataSourceTags = fullTags.filter({ (s) -> Bool in
212+ s.lowercased().contains(text.lowercased())
213+ })
256 tableView.reloadData()
214 tableView.reloadData()
257 default:
215 default:
258 break
216 break
@@ -260,16 +218,16 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
260 }
218 }
261
219
262 func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
220 func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
263− activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
264 if searchBar.isFirstResponder {
221 if searchBar.isFirstResponder {
265 switch activeDataSource{
222 switch activeDataSource{
266 case .people :
223 case .people :
267− dataSourcePeople = Model.Channels.fullPeople
224+ dataSourcePeople = fullPeople
268 dataSourceTags = []
225 dataSourceTags = []
269 case .tags:
226 case .tags:
270 dataSourceTags = fullTags
227 dataSourceTags = fullTags
271 dataSourcePeople = []
228 dataSourcePeople = []
272 }
229 }
230+ activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
273 if (!(searchBar.text?.isEmpty ?? true))
231 if (!(searchBar.text?.isEmpty ?? true))
274 {
232 {
275 filterTableView(ind: selectedScope, text: searchBar.text!)
233 filterTableView(ind: selectedScope, text: searchBar.text!)
@@ -278,14 +236,13 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
278 } else if !(searchBar.isFirstResponder){
236 } else if !(searchBar.isFirstResponder){
279 switch activeDataSource{
237 switch activeDataSource{
280 case .people :
238 case .people :
281− dataSourcePeople = channel!.people.map({ (item) -> Model.Users in
239+ dataSourcePeople = channel!.people
282− Model.Channels.fullPeopleDict[item]!
283− })
284 dataSourceTags = []
240 dataSourceTags = []
285 case .tags:
241 case .tags:
286 dataSourceTags = channel!.tags
242 dataSourceTags = channel!.tags
287 dataSourcePeople = []
243 dataSourcePeople = []
288 }
244 }
245+ activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
289 tableView.reloadData()
246 tableView.reloadData()
290 }
247 }
291 }
248 }
@@ -293,9 +250,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
293 func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
250 func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
294 switch activeDataSource{
251 switch activeDataSource{
295 case .people :
252 case .people :
296− dataSourcePeople = channel!.people.map({ (item) -> Model.Users in
253+ dataSourcePeople = channel!.people
297− Model.Channels.fullPeopleDict[item]!
298− })
299 dataSourceTags = []
254 dataSourceTags = []
300 case .tags:
255 case .tags:
301 dataSourceTags = channel!.tags
256 dataSourceTags = channel!.tags
@@ -308,7 +263,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
308 func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
263 func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
309 switch activeDataSource{
264 switch activeDataSource{
310 case .people :
265 case .people :
311− dataSourcePeople = Model.Channels.fullPeople
266+ dataSourcePeople = fullPeople
312 dataSourceTags = []
267 dataSourceTags = []
313 case .tags:
268 case .tags:
314 dataSourceTags = fullTags
269 dataSourceTags = fullTags
GDproject/Controller/ News and channels/ChannelListController.swift+38−42
@@ -13,28 +13,18 @@ struct ChannelData{
13 var subtitle = String()
13 var subtitle = String()
14}
14}
15
15
16−protocol ChannelListData: class {
17− func reloadData (with channels: [Model.Channels])
18−}
19−
20// TODO: make search controller availiable
16// TODO: make search controller availiable
21−class ChannelListController: UITableViewController {
17+class ChannelListController: UITableViewController, DataDelegate {
22
18
23 // MARK: - Output -
19 // MARK: - Output -
24 var onChannelSelected: ((Model.Channels) -> Void)?
20 var onChannelSelected: ((Model.Channels) -> Void)?
25− var onEditingModeBegins: ((Model.Channels, IndexPath)->Void)?
26
21
27 // MARK: - filter search controller
22 // MARK: - filter search controller
28 var filteredDataSource = [Model.Channels]()
23 var filteredDataSource = [Model.Channels]()
29
24
25+ var myProtocol: DataDelegate?
30 var displayingChannel: Model.Channels?
26 var displayingChannel: Model.Channels?
31
27
32− var toReload: Bool = false {
33− didSet {
34− tableView.reloadData()
35− }
36− }
37−
38 var isFiltering: Bool {
28 var isFiltering: Bool {
39 return searchController.isActive && !searchBarIsEmpty()
29 return searchController.isActive && !searchBarIsEmpty()
40 }
30 }
@@ -53,16 +43,13 @@ class ChannelListController: UITableViewController {
53 }
43 }
54
44
55 func passData(for row: Int, channel: Model.Channels) {
45 func passData(for row: Int, channel: Model.Channels) {
56− // dataSource[row] = channel
46+ dataSource[row] = channel
57 }
47 }
58
48
59 var searchController = UISearchController(searchResultsController: nil)
49 var searchController = UISearchController(searchResultsController: nil)
60
50
61 override func viewDidLoad() {
51 override func viewDidLoad() {
62 super.viewDidLoad()
52 super.viewDidLoad()
63−
64− Model.usersAllGet()
65−
66 setUpNavigationBar()
53 setUpNavigationBar()
67 navigationItem.title = "Channels"
54 navigationItem.title = "Channels"
68 searchController.searchResultsUpdater = self
55 searchController.searchResultsUpdater = self
@@ -77,35 +64,35 @@ class ChannelListController: UITableViewController {
77 navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addChannel))]
64 navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addChannel))]
78 }
65 }
79
66
80− override func viewDidAppear(_ animated: Bool)
67+ override func viewWillAppear(_ animated: Bool)
81 {
68 {
82− super.viewDidAppear(animated)
69+ super.viewWillAppear(animated)
83 searchController.isActive = false
70 searchController.isActive = false
84− askForUpdates()
85− }
86−
87− func askForUpdates(){
88 Model.channelsList { [weak self] (channels) in
71 Model.channelsList { [weak self] (channels) in
89 self?.dataSource = [ChannelListController.generalChannel] + channels
72 self?.dataSource = [ChannelListController.generalChannel] + channels
90− self?.toReload = true
91 }
73 }
92 }
74 }
93
75
94− override func viewWillAppear(_ animated: Bool) {
95− super.viewWillAppear(true)
96− //askForUpdates()
97− tabBarController?.tabBar.isHidden = false
98− }
99−
100 @objc func addChannel()
76 @objc func addChannel()
101 {
77 {
102 // editing mode is on automatically
78 // editing mode is on automatically
79+ let vc = storyboard?.instantiateViewController(withIdentifier: channelControllerId) as! ChannelController
80+ vc.index = 1
81+ vc.myProtocol = self
103− onEditingModeBegins?(Model.Channels(people: [], name: "Untitled", id: 0, tags: []),IndexPath(row: 1, section: 0))
82+ vc.channel = Model.Channels(people: [], name: "Untitled", tags: [])
83+ navigationController?.pushViewController(vc, animated: true)
104 }
84 }
105
85
106 static let generalChannel = Model.Channels(people: [], name: "General", id: -1, tags: [])
86 static let generalChannel = Model.Channels(people: [], name: "General", id: -1, tags: [])
107
87
108− var dataSource : [Model.Channels] = [ ChannelListController.generalChannel ]
88+ var dataSource : [Model.Channels] = [
89+ Model.Channels(people: [], name: "General", id: -1, tags: [])
90+ ]
91+ {
92+ didSet{
93+ self.tableView.reloadData()
94+ }
95+ }
109
96
110 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
97 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
111 if isFiltering {
98 if isFiltering {
@@ -144,35 +131,44 @@ class ChannelListController: UITableViewController {
144
131
145 override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
132 override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
146 {
133 {
134+
147− let editButton = UITableViewRowAction(style: .normal, title: "Edit") { [unowned self] (rowAction, indexPath) in
135+ let editButton = UITableViewRowAction(style: .normal, title: "Edit") { [weak self] (action, indexPath) in
136+ let vc = self?.storyboard?.instantiateViewController(withIdentifier: channelControllerId) as! ChannelController
137+ vc.index = indexPath.row
138+ vc.myProtocol = self!
148− self.onEditingModeBegins?(self.dataSource[indexPath.row], indexPath)
139+ vc.channel = self?.dataSource[indexPath.row]
140+ self?.navigationController?.pushViewController(vc, animated: true)
149 }
141 }
142+ editButton.backgroundColor = .green
150
143
151− editButton.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
152
144
153 let deleteButton = UITableViewRowAction(style: .normal, title: "Delete") { [weak self] (action, indexPath) in
145 let deleteButton = UITableViewRowAction(style: .normal, title: "Delete") { [weak self] (action, indexPath) in
154−
155− Model.channelsDelete(by: self!.dataSource[indexPath.row].id!, completion: {
146+ if (self!.dataSource[indexPath.row].id == self!.displayingChannel?.id ?? -1)
156− print("хз что тут делать при успехе")
147+ {
148+ self?.myProtocol?.passData(for: 0, channel: self!.dataSource[0])
157− })
149+ }
158−
159 self?.tableView.beginUpdates()
150 self?.tableView.beginUpdates()
160 self?.dataSource.remove(at: indexPath.row)
151 self?.dataSource.remove(at: indexPath.row)
161 self?.tableView.deleteRows(at: [indexPath], with: .none)
152 self?.tableView.deleteRows(at: [indexPath], with: .none)
162 self?.tableView.endUpdates()
153 self?.tableView.endUpdates()
163 }
154 }
155+ deleteButton.backgroundColor = .red
164
156
165− deleteButton.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
166
157
167 return [editButton, deleteButton]
158 return [editButton, deleteButton]
168 }
159 }
169
160
161+ // TODO: remove popping
170 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
162 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
171 {
163 {
172 if isFiltering {
164 if isFiltering {
173− onChannelSelected?(filteredDataSource[indexPath.row])
165+ //onChannelSelected?(filteredDataSource[indexPath.row])
166+ myProtocol?.passData(for: 0, channel: filteredDataSource[indexPath.row])
167+ navigationController?.popViewController(animated: true)
174 } else {
168 } else {
169+ myProtocol?.passData(for: 0, channel: dataSource[indexPath.row])
170+ navigationController?.popViewController(animated: true)
175− onChannelSelected?(dataSource[indexPath.row])
171+ //onChannelSelected?(ChannelListController.dataSource[indexPath.row])
176 }
172 }
177 }
173 }
178}
174}
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/ChannelsCoordinator.swiftnew file+55
@@ -0,0 +1,55 @@
1+//
2+// ChannelsCoordinator.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+
12+final class ChannelsCoordinator{
13+
14+ // MARK: - Properties
15+ private var channel: Model.Channels { didSet { updateInterfaces() } }
16+ private weak var navigationController: UINavigationController?
17+
18+ // MARK:- Init
19+ init(currentChannel: Model.Channels, navigationController: UINavigationController) {
20+ self.channel = currentChannel
21+ self.navigationController = navigationController
22+ }
23+
24+ func start(){
25+ showCurrentChannel()
26+ }
27+
28+ // MARK: - Private implementation
29+ private func showListOfChannels(){
30+ let controller = UIStoryboard.makeChannelsListController()
31+ controller.onChannelSelected = { [weak self] channel
32+ in
33+ self?.channel = channel
34+ _ = self?.navigationController?.popViewController(animated: true)
35+ }
36+ navigationController?.pushViewController(controller, animated: true)
37+ }
38+
39+ private func showCurrentChannel(){
40+ let controller = UIStoryboard.makeNewsController()
41+ controller.channel = channel
42+ controller.onSelectChannel = { [weak self] in
43+ self?.showListOfChannels()
44+ }
45+ navigationController?.setViewControllers([controller], animated: false)
46+ //navigationController?.pushViewController(controller, animated: false)
47+ }
48+
49+ // MARK:- update only viewControllers which are depandable on chosen channel
50+ private func updateInterfaces() {
51+ navigationController?.viewControllers.forEach {
52+ ($0 as? UpdateableWithChannel)?.channel = channel
53+ }
54+ }
55+}
GDproject/Controller/ News and channels/FullPostController.swift+19−16
@@ -12,7 +12,6 @@ import TinyConstraints
12class FullPostController: UITableViewController {
12class FullPostController: UITableViewController {
13
13
14 var post: Model.Posts?
14 var post: Model.Posts?
15− var type: HeaderType = .NONE
16
15
17 override func viewDidLoad() {
16 override func viewDidLoad() {
18 super.viewDidLoad()
17 super.viewDidLoad()
@@ -25,10 +24,27 @@ class FullPostController: UITableViewController {
25
24
26 func setUpNavigationBar(){
25 func setUpNavigationBar(){
27 navigationItem.largeTitleDisplayMode = .never
26 navigationItem.largeTitleDisplayMode = .never
28− navigationItem.title = "Post"
27+ navigationItem.title = "\(post?.authorId ?? 0)"
28+ navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(self.options))]
29 }
29 }
30
30
31−
31+ @objc func options(){
32+ // drafts
33+ // saved
34+
35+ let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
36+ let editAction = UIAlertAction(title: "Send via message", style: .default)
37+ let shareAction = UIAlertAction(title: "Send via project", style: .default)
38+ let settingsAction = UIAlertAction(title: "Copy link", style: .default)
39+ let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
40+
41+ optionMenu.addAction(editAction)
42+ optionMenu.addAction(shareAction)
43+ optionMenu.addAction(settingsAction)
44+ optionMenu.addAction(cancelAction)
45+
46+ self.present(optionMenu, animated: true, completion: nil)
47+ }
32 // MARK: - Table view data source
48 // MARK: - Table view data source
33
49
34 override func numberOfSections(in tableView: UITableView) -> Int {
50 override func numberOfSections(in tableView: UITableView) -> Int {
@@ -79,19 +95,6 @@ class FullPostController: UITableViewController {
79
95
80
96
81 cell.fill(with: PostCellData.create(with: post!.body), true, post: post!)
97 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−
95 cell.selectionStyle = .none
98 cell.selectionStyle = .none
96 return cell
99 return cell
97 }
100 }
GDproject/Controller/ News and channels/NewPostViewController.swift+39−126
@@ -10,39 +10,17 @@ import UIKit
10import Cartography
10import Cartography
11import Marklight
11import Marklight
12import TinyConstraints
12import TinyConstraints
13−import TaggerKit
14−// import WSTagsField
15
13
16−class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
14+class NewPostViewController: UIViewController, UITextViewDelegate {
17−{
18− func receiveTags(tags: [String]) {
19− currentTags = tags
20− }
21
15
22 @IBOutlet weak var view1: UIView!
16 @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()
40 // Keep strong instance of the `NSTextStorage` subclass
17 // Keep strong instance of the `NSTextStorage` subclass
41 let textStorage = MarklightTextStorage()
18 let textStorage = MarklightTextStorage()
42
19
43− static var draft: String = ""
20+ weak var parentVC: NewsController?
44− static var hashTagsDraft: [String] = [ ]
21+ var myProtocol: NewPostDelegate?
45
22
23+ static var draft: String = ""
46 var textView: UITextView!
24 var textView: UITextView!
47
25
48 // buttons for attaching images
26 // buttons for attaching images
@@ -72,49 +50,16 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
72
50
73 setUpMD()
51 setUpMD()
74 setUpTextView()
52 setUpTextView()
75− // setUpAccessoryView()
53+ setUpAccessoryView()
76− //setUpTagsView()
77 }
54 }
78
55
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− }*/
108
56
109 override func viewWillAppear(_ animated: Bool) {
57 override func viewWillAppear(_ animated: Bool) {
110 super.viewWillAppear(animated)
58 super.viewWillAppear(animated)
111
59
112− //navigationController?.navigationBar.prefersLargeTitles = false
60+ navigationController?.navigationBar.prefersLargeTitles = false
113− navigationItem.largeTitleDisplayMode = .never
114 navigationItem.title = "New post"
61 navigationItem.title = "New post"
115 textView.text = NewPostViewController.draft
62 textView.text = NewPostViewController.draft
116− // tagsField.addTags(NewPostViewController.hashTagsDraft)
117−
118 }
63 }
119
64
120 func setUpAccessoryView(){
65 func setUpAccessoryView(){
@@ -141,7 +86,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
141 func setUpTextView(){
86 func setUpTextView(){
142 view.addConstraint(bottomTextViewConstraint)
87 view.addConstraint(bottomTextViewConstraint)
143 view1.addSubview(textView)
88 view1.addSubview(textView)
144− textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(8) + .right(8))
89+ textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(40+8) + .right(8))
145
90
146 if #available(iOS 11.0, *) {
91 if #available(iOS 11.0, *) {
147 textView.smartDashesType = .no
92 textView.smartDashesType = .no
@@ -206,11 +151,27 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
206
151
207 @objc func addMathBrackets()
152 @objc func addMathBrackets()
208 {
153 {
209− // nothing
154+ if textView.text.count != 0 && textView.text.last != "\n" {
155+ textView.insertText("\n\\[\n ")
156+ }
157+ else {
158+ textView.insertText("\\[\n ")
159+ }
160+
161+ if let selectedRange = textView.selectedTextRange
162+ {
163+ textView.insertText("\n\\]\n")
164+
165+ if let newPosition = textView.position(from: selectedRange.start, offset: 0)
166+ {
167+ // set the new position
168+ textView.selectedTextRange = textView.textRange(from: newPosition, to: newPosition)
169+ }
170+ }
210 }
171 }
211
172
212 func setUpMD(){
173 func setUpMD(){
213− textStorage.marklightTextProcessor.codeColor = UIColor.gray
174+ textStorage.marklightTextProcessor.codeColor = UIColor.orange
214 textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
175 textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
215 textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
176 textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
216 textStorage.marklightTextProcessor.codeFontName = "Courier"
177 textStorage.marklightTextProcessor.codeFontName = "Courier"
@@ -232,27 +193,10 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
232 var indexOfPost = 0
193 var indexOfPost = 0
233 // MARK:- new post
194 // MARK:- new post
234 @objc func newPost(){
195 @objc func newPost(){
235− self.navigationItem.title = "Sending..."
236− Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: currentTags) {
196+ Model.createAndPublish(body: [ Model.Attachments(markdown: textView!.text) ], tags: ["ПИ", "люблюСвоюРаботу", "работаРулит", "Шершаков"])
237− [weak self] in
238−
239− switch $0 {
240− case .success1, .success:
241− NewPostViewController.draft = ""
242− NewPostViewController.hashTagsDraft = []
243− self?.moveBackToParentVC?()
244− default:
245− self?.showAlertOn(result: $0)
246− self?.navigationItem.title = "New post"
247− }
248−
249− }
250−
251− // NewPostViewController.draft = ""
252− // NewPostViewController.hashTagsDraft = []
253 // adding row to uiTableView after adding new post
197 // adding row to uiTableView after adding new post
254 // myProtocol?.addPost(post: p)
198 // myProtocol?.addPost(post: p)
255− // moveBackToParentVC?()
199+ moveBackToParentVC()
256 // somewhere here i will be sending server notifications about new post arrival
200 // somewhere here i will be sending server notifications about new post arrival
257 }
201 }
258
202
@@ -264,8 +208,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
264 [weak self]
208 [weak self]
265 _ in
209 _ in
266 NewPostViewController.draft = self?.textView.text ?? ""
210 NewPostViewController.draft = self?.textView.text ?? ""
267− NewPostViewController.hashTagsDraft = self?.currentTags ?? []
268− self?.moveBackToParentVC?()
211+ self?.moveBackToParentVC()
269 }
212 }
270
213
271 let deleteAction = UIAlertAction(title: "Delete draft", style: .destructive)
214 let deleteAction = UIAlertAction(title: "Delete draft", style: .destructive)
@@ -273,8 +216,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
273 [weak self] (_)
216 [weak self] (_)
274 in
217 in
275 NewPostViewController.draft = ""
218 NewPostViewController.draft = ""
276− NewPostViewController.hashTagsDraft = []
277− self?.moveBackToParentVC?()
219+ self?.moveBackToParentVC()
278 }
220 }
279
221
280 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
222 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
@@ -291,7 +233,16 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
291 actionSaveDraft()
233 actionSaveDraft()
292 }
234 }
293
235
294− var moveBackToParentVC: (()->())?
236+ func moveBackToParentVC(){
237+ let transition = CATransition()
238+ transition.duration = 0.5
239+ transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
240+ transition.type = CATransitionType.reveal
241+ transition.subtype = CATransitionSubtype.fromBottom
242+ navigationController?.view.layer.add(transition, forKey: nil)
243+ navigationController?.popViewController(animated: false)
244+ textView!.resignFirstResponder()
245+ }
295
246
296
247
297 func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
248 func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
@@ -304,42 +255,4 @@ class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
304 rect.size.height = rect.size.height + textView.textContainerInset.bottom
255 rect.size.height = rect.size.height + textView.textContainerInset.bottom
305 textView.scrollRectToVisible(rect, animated: animated)
256 textView.scrollRectToVisible(rect, animated: animated)
306 }
257 }
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−
345}
258}
GDproject/Controller/ News and channels/NewsController.swift+168−72
@@ -12,49 +12,68 @@ import Cartography
12
12
13protocol UpdateableWithChannel: class {
13protocol UpdateableWithChannel: class {
14 var channel: Model.Channels? { get set }
14 var channel: Model.Channels? { get set }
15− func updateChannel(on channel: Model.Channels)
16}
15}
17−
16+protocol NewPostDelegate {
17+ func addPost(post: Post)
18+}
18protocol UpdateableWithUser: class {
19protocol UpdateableWithUser: class {
19 var user: Model.Users? { get set }
20 var user: Model.Users? { get set }
20}
21}
21// MARK:- Controller with posts and channels availiable.
22// MARK:- Controller with posts and channels availiable.
22// Search is availiable within every table (posts and channels). Has button-functionality for boths post and chnnels
23// Search is availiable within every table (posts and channels). Has button-functionality for boths post and chnnels
23−class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWithChannel, UISearchResultsUpdating
24+class NewsController: UITableViewController, UISearchControllerDelegate, NewPostDelegate, UpdateableWithChannel, DataDelegate
24{
25{
25− func updateChannel(on channel: Model.Channels) {
26+ func passData(for row: Int, channel: Model.Channels) {
27+ if channel.id == -1{
26− self.channel = channel
28+ self.channel = nil
27− news.currChannel = channel
29+ } else {
28− decideWhatChannelDisplay()
30+ self.channel = channel
31+ }
29 }
32 }
30
33
31− var changedChannelName: ((String)->())?
34+ var dictionary: [Int: Model.Users]? {
35+ didSet{
36+
37+ var newPosts: [Model.Posts] = []
38+
39+ posts!.forEach({ (post) in
40+ newPosts.append(Model.Posts(body: post.body, authorId: post.authorId, id: post.id, user: dictionary![post.authorId]!, date: post.updated, tags: post.tags))
41+ })
42+
43+ news.dataSourse = newPosts
44+ print("and heeeere in dict")
45+ tableView.reloadData()
46+ }
47+ }
32
48
33− @IBOutlet weak var tableView: UITableView!
49+ var posts: [Model.Posts]? {
50+ didSet{
51+
52+ }
53+ }
34
54
35− var channel: Model.Channels?
55+ var channel: Model.Channels? {
36− var anonymousChannel: (users: [Int: Model.Users], posts: [Model.Posts])?
56+ didSet{
57+ navigationItem.title = channel?.name ?? ""
58+ }
59+ }
37
60
38 // MARK: - Output -
61 // MARK: - Output -
39 var onSelectChannel: (() -> Void)?
62 var onSelectChannel: (() -> Void)?
63+
64+ func addPost(post: Post) {
65+ //news.dataSourse.insert(post, at: 0)
66+ }
40
67
41− var searchController: UISearchController?
68+ var searchController = UISearchController(searchResultsController: nil)
42
69
43 var news = NewsVC()
70 var news = NewsVC()
44− var type: HeaderType? = .NEWS
45
71
46 var refreshContr = UIRefreshControl()
72 var refreshContr = UIRefreshControl()
47
73
48 override func viewDidLoad()
74 override func viewDidLoad()
49 {
75 {
50 super.viewDidLoad()
76 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 ..."
77 navigationItem.title = "Loading ..."
59 tableView.refreshControl = refreshContr
78 tableView.refreshControl = refreshContr
60 // Configure Refresh Control
79 // Configure Refresh Control
@@ -65,95 +84,172 @@ class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWi
65
84
66 setUpSearchContr()
85 setUpSearchContr()
67
86
68− // navigationItem.
69 news.viewController = self
87 news.viewController = self
70− news.type = type == .NEWS ? .NEWS : type!
88+ news.type = .NEWS
71− news.currChannel = channel
72
89
73 setUpNavigationItemsforPosts()
90 setUpNavigationItemsforPosts()
91+
92+ //setUpBanner()
74 }
93 }
75
94
76 func setUpSearchContr(){
95 func setUpSearchContr(){
77− searchController?.delegate = self
96+ searchController.delegate = self
78− searchController?.obscuresBackgroundDuringPresentation = false
97+ searchController.obscuresBackgroundDuringPresentation = false
79 navigationItem.searchController = searchController
98 navigationItem.searchController = searchController
80 definesPresentationContext = true
99 definesPresentationContext = true
81− searchController?.searchResultsUpdater = self
82− searchController?.searchBar.placeholder = "Search tags"
100+ searchController.searchBar.placeholder = "Search anything"
83 }
101 }
84
102
85− @objc func refreshPostsData( _ ff: UIRefreshControl) {
103+ @objc func refreshPostsData( _ ff: UIRefreshControl){
86− decideWhatChannelDisplay()
104+ print("I am here")
105+ Model.getLast { [weak self] (tuple) in
106+ self?.posts = tuple.posts
107+ self?.dictionary = tuple.users
108+ self?.refreshContr.endRefreshing()
109+ }
87 }
110 }
88
111
89 deinit {
112 deinit {
90 print("news clear")
113 print("news clear")
91 }
114 }
92
115
116+ let label : UILabel = {
117+ let label = UILabel()
118+ label.text = "No posts to display yet!"
119+ label.font = UIFont.systemFont(ofSize: 18)
120+ label.textColor = .black
121+ label.isHidden = true
122+ label.numberOfLines = 0
123+ return label
124+ }()
125+
93 override func viewWillAppear(_ animated: Bool) {
126 override func viewWillAppear(_ animated: Bool) {
94 super.viewWillAppear(animated)
127 super.viewWillAppear(animated)
95− searchController?.isActive = false
128+ searchController.isActive = false
96 // TODO:- display something if no posts are availiable
129 // TODO:- display something if no posts are availiable
97
130
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 {
131+ if let channel = channel, let id = channel.id {
108−
132+
109− Model.getAnonymousChannel(by: channel) { [weak self] in
133+ Model.getChannel(with: id) { [weak self] in
110− self?.news.dataSourse = $0.posts
134+ self?.posts = $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
135+ self?.dictionary = $0.users
120− self?.refreshContr.endRefreshing()
121− self?.changedChannelName?("General")
122− }
123 }
136 }
124− default:
137+
125− refreshContr.endRefreshing()
138+ } else{
126− break
139+
140+ navigationItem.title = "@&% General"
141+ Model.getLast { [weak self] in
142+ self?.posts = $0.posts
143+ self?.dictionary = $0.users
144+ }
145+
127 }
146 }
128
147
148+ // tableView.reloadData()
129 }
149 }
130
150
131 func setUpNavigationItemsforPosts(){
151 func setUpNavigationItemsforPosts(){
152+ navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(self.writePost(_:))),UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(self.showChannels(_:)))
153+ ]
132 tableView.delegate = news
154 tableView.delegate = news
133 tableView.dataSource = news
155 tableView.dataSource = news
134 tableView.reloadData()
156 tableView.reloadData()
135 }
157 }
136
158
137− func updateSearchResults(for searchController: UISearchController)
159+ // MARK:- attempt with coordinator
160+ @objc func showChannels(_ barItem: UIBarButtonItem){
161+ let vc = UIStoryboard.makeChannelsListController()
162+ vc.myProtocol = self
163+ vc.displayingChannel = channel
164+ self.navigationController?.pushViewController(vc, animated: true)
165+ }
166+
167+ @objc func writePost(_ barItem: UIBarButtonItem)
138 {
168 {
139− let filteredData = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: searchController.searchBar.text?.lowercased() ?? "")
169+ let vc = storyboard?.instantiateViewController(withIdentifier: "NewPostViewController") as! NewPostViewController
140−
170+
141− // Apply the filtered results to the search results table.
171+ vc.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Post", style: .plain, target: vc, action: #selector(vc.newPost))
142− if let resultsController = searchController.searchResultsController as? TagsSuggestionController {
172+ vc.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: vc, action: #selector(vc.closeView))
143− resultsController.suggestions = filteredData
173+
144− resultsController.tableView.reloadData()
174+ vc.myProtocol = self
145− }
175+
176+ let transition = CATransition()
177+ transition.duration = 0.5
178+ transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
179+ transition.type = CATransitionType.moveIn
180+ transition.subtype = CATransitionSubtype.fromTop
181+ navigationController?.view.layer.add(transition, forKey: nil)
182+ navigationController?.pushViewController(vc, animated: false)
146 }
183 }
147
184
148− func willPresentSearchController(_ searchController: UISearchController) {
185+ // for animating the banner
149− searchController.searchResultsController?.view.isHidden = false;
186+ var topConstraint: NSLayoutConstraint?
187+
188+ let bannerView: UIView = {
189+ let view = UIView()
190+ view.backgroundColor = .blue
191+ view.layer.cornerRadius = 25.0
192+ view.clipsToBounds = true
193+ return view
194+ }()
195+
196+ let statusLabel: UILabel = {
197+ let label = UILabel()
198+ label.text = "-"
199+ label.textColor = .white
200+ label.textAlignment = .center
201+ return label
202+ }()
203+
204+ // MARK:- banner
205+ private func setUpBanner()
206+ {
207+ view.addSubview(bannerView)
208+ bannerView.addSubview(statusLabel)
209+ statusLabel.edgesToSuperview()
210+
211+ let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
212+
213+ bannerView.addGestureRecognizer(tap)
214+ topConstraint = NSLayoutConstraint(item: bannerView, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .top, multiplier: 1, constant: -300)
215+ view.addConstraint(topConstraint!)
216+
217+ bannerView.edgesToSuperview(excluding: [.bottom, .top, .left], insets: .right(20), usingSafeArea: true)
218+ bannerView.height(50)
219+ bannerView.width(50)
150 }
220 }
151
221
152− func didPresentSearchController(_ searchController: UISearchController) {
222+ // when table is scrolling no deletion is availiable
153− searchController.searchResultsController?.view.isHidden = false;
223+ @objc func handleTap(sender: UITapGestureRecognizer? = nil) {
224+ let indexPath = IndexPath(row: 0, section: 0)
225+ self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
226+// isBannerVisible = false
227+// changeConstraint(isVisible: false)
228+ }
229+
230+ // animation for banner
231+ func changeConstraint(isVisible: Bool){
232+ topConstraint?.constant = isVisible ? 50 : -300
233+
234+ UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
235+ self.view.layoutIfNeeded()
236+ }) { (completed) in
237+
238+ }
154 }
239 }
155
240
156− func didDismissSearchController(_ searchController: UISearchController) {
241+ var isBannerVisible: Bool = false
157− searchController.searchBar.text = ""
242+
243+ override func scrollViewDidScroll(_ scrollView: UIScrollView) {
244+ print(scrollView.contentOffset.y)
245+ if scrollView.contentOffset.y >= 50 && !isBannerVisible{
246+ isBannerVisible = true
247+ changeConstraint(isVisible: true)
248+ }
249+
250+ if isBannerVisible && scrollView.contentOffset.y == 0{
251+ isBannerVisible = false
252+ changeConstraint(isVisible: false)
253+ }
158 }
254 }
159}
255}
GDproject/Controller/ News and channels/NewsVC.swift+14−62
@@ -19,40 +19,20 @@ struct PostCellData{
19
19
20 let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
20 let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
21 markdownParser.enabledElements = .disabledAutomaticLink
21 markdownParser.enabledElements = .disabledAutomaticLink
22− markdownParser.code.font = UIFont(name: "Menlo", size: 16)
23− markdownParser.code.textBackgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
22+ markdownParser.code.textBackgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
24− markdownParser.code.color = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
25
23
26 return markdownParser.parse(markdown)
24 return markdownParser.parse(markdown)
27 }
25 }
28}
26}
29
27
30−class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
28+class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
31
29
32−
30+ var dataSourse: [Model.Posts] = []{
33− var onChannelDidChange: ((([Int: Model.Users],[Model.Posts]))->())?
34−
35− var onFullPost: ((HeaderType, Model.Posts)->())?
36−
37− var dictionary: [Int: Model.Users] = [:] {
38 didSet {
31 didSet {
39−
32+ cellDataSourse = []
40− dataSourse = dataSourse.map {
33+ dataSourse.forEach { (item) in
41− var copy = $0
34+ cellDataSourse.append(PostCellData(attributedData: PostCellData.create(with: item.body)))
42− copy.user = dictionary[$0.authorId]
43− return copy
44 }
35 }
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 }
36 }
57 }
37 }
58
38
@@ -68,7 +48,11 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
68
48
69 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
49 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
70 {
50 {
51+ tableView.deselectRow(at: indexPath, animated: true)
52+ let vc = viewController!.storyboard!.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
53+
71− onFullPost?(type, dataSourse[indexPath.row])
54+ vc.post = dataSourse[indexPath.row]
55+ viewController!.navigationController!.pushViewController(vc, animated: true)
72 }
56 }
73
57
74 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
58 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@@ -88,14 +72,9 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
88 vc.idProfile = id
72 vc.idProfile = id
89 self?.viewController!.navigationController!.pushViewController(vc, animated: true)
73 self?.viewController!.navigationController!.pushViewController(vc, animated: true)
90 }
74 }
91−
75+ case .NONE:
92− cell.onAnonymousChannelDisplay = {
93− [weak self] in
94− (self?.viewController as? UpdateableWithChannel)?.updateChannel(on: Model.Channels(people: [], name: $0, id: 0, tags: [$0]))
95− }
96− default:
97 cell.onUserDisplay = { (id) in
76 cell.onUserDisplay = { (id) in
98− print("tapped when profile is opened already \(id)")
77+ print("tapped when profile is open already \(id)")
99 }
78 }
100 }
79 }
101
80
@@ -110,37 +89,10 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
110 func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
89 func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
111 return 100.0
90 return 100.0
112 }
91 }
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− }
140}
92}
141
93
94+
142enum HeaderType {
95enum HeaderType {
143 case NONE
96 case NONE
144 case NEWS
97 case NEWS
145− case ANONYMOUS
146}
98}
GDproject/Controller/ News and channels/PostViewCell.swift+7−27
@@ -8,15 +8,13 @@
8
8
9import UIKit
9import UIKit
10import Cartography
10import Cartography
11+import MarkdownKit
11import TinyConstraints
12import TinyConstraints
12
13
13class PostViewCell: UITableViewCell
14class PostViewCell: UITableViewCell
14{
15{
15−
16 var onUserDisplay: ((Int)->())?
16 var onUserDisplay: ((Int)->())?
17
17
18− var onAnonymousChannelDisplay: ((String)->())?
19−
20 let nameLabel: UIButton = {
18 let nameLabel: UIButton = {
21 let button = UIButton()
19 let button = UIButton()
22 button.setTitleColor(.black, for: .normal)
20 button.setTitleColor(.black, for: .normal)
@@ -42,7 +40,6 @@ class PostViewCell: UITableViewCell
42
40
43 let shareButton: UIButton = {
41 let shareButton: UIButton = {
44 let button = UIButton(type: UIButton.ButtonType.detailDisclosure)
42 let button = UIButton(type: UIButton.ButtonType.detailDisclosure)
45− button.isHidden = true
46 return button
43 return button
47 }()
44 }()
48
45
@@ -86,12 +83,7 @@ class PostViewCell: UITableViewCell
86
83
87 nameLabel.setTitle("\(post.user?.firstName ?? "") \(post.user?.lastName ?? "")", for: .normal)
84 nameLabel.setTitle("\(post.user?.firstName ?? "") \(post.user?.lastName ?? "")", for: .normal)
88 nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
85 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)"
86+ fullNameLabel.text = "\(post.authorId)"
94− }
95
87
96 setUpInStackView(isFullVersoin)
88 setUpInStackView(isFullVersoin)
97 }
89 }
@@ -123,8 +115,8 @@ class PostViewCell: UITableViewCell
123 for hash in hashtags {
115 for hash in hashtags {
124 let button = UIButton()
116 let button = UIButton()
125 button.setTitle("#" + hash, for: .normal)
117 button.setTitle("#" + hash, for: .normal)
126− button.addTarget(self, action: #selector(setAnonymousChannel(on:)), for: .touchUpInside)
118+ //button.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
127− // button.addGestureRecognizer(longPressRecognizer)
119+ //button.layer.cornerRadius = 10
128 button.titleLabel?.font = UIFont.monospacedDigitSystemFont(ofSize: 15, weight: .semibold)
120 button.titleLabel?.font = UIFont.monospacedDigitSystemFont(ofSize: 15, weight: .semibold)
129 button.setTitleColor(#colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1), for: .normal)
121 button.setTitleColor(#colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1), for: .normal)
130 buttons.append(button)
122 buttons.append(button)
@@ -150,13 +142,7 @@ class PostViewCell: UITableViewCell
150 contentView.addSubview(mainView)
142 contentView.addSubview(mainView)
151 mainView.edgesToSuperview(excluding: [.top, .bottom])
143 mainView.edgesToSuperview(excluding: [.top, .bottom])
152 mainView.topToBottom(of: nameStackView, offset: 5)
144 mainView.topToBottom(of: nameStackView, offset: 5)
153−
154− // TODO:- change!!!!!!!!!!!!
155− if hashtags.isEmpty{
156− mainView.height(0)
157− } else {
158− mainView.height(30)
145+ mainView.height(30)
159− }
160
146
161 let stackView = MyStackView(arrangedSubviews: views)
147 let stackView = MyStackView(arrangedSubviews: views)
162 stackView.isFull = full
148 stackView.isFull = full
@@ -182,13 +168,7 @@ class PostViewCell: UITableViewCell
182 }
168 }
183
169
184 @objc func displayProfile(){
170 @objc func displayProfile(){
171+ print("buttonTapped")
185− if let id = post?.authorId {
172+ onUserDisplay?(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 }
173 }
194}
174}
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/Coordinator tab bar?/TabbarCoordinator.swiftnew file+14
@@ -0,0 +1,14 @@
1+import UIKit
2+
3+class TabbarCoordinator{
4+ var window: UIWindow!
5+
6+ func start(){
7+ let tabbar = UIStoryboard.tabBarController()
8+ window.rootViewController = tabbar
9+ }
10+
11+ init(window: UIWindow) {
12+ self.window = window
13+ }
14+}
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/LogInCoordinator.swiftnew file+48
@@ -0,0 +1,48 @@
1+//
2+// LogInCoordinator.swift
3+// GDproject
4+//
5+// Created by cstore on 23/02/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class LogInCoordinator{
12+
13+ private weak var navigationController: UINavigationController?
14+ private var window: UIWindow!
15+ // MARK:- Init
16+ init(navigationController: UINavigationController, window: UIWindow) {
17+ self.navigationController = navigationController
18+ self.window = window
19+ }
20+
21+ func start(){
22+ showLogInPage()
23+ }
24+
25+ // MARK: - Private implementation
26+// private func showStatusPage(){
27+// let controller = TabbarCoordinator(window: window)
28+// controller.start()
29+// }
30+
31+ private func showLogInPage(){
32+ let controller = UIStoryboard.makeLogIn()
33+
34+ controller.onLogIn = {
35+ (id) in Model.authenticate(with: id) {
36+ (res) in
37+
38+ if (res) { DataStorage.standard.setUserKey(with: id) }
39+ else { DataStorage.standard.setUserKey(with: 0) }
40+
41+ controller.authenticateSucceeded = res
42+ }
43+ }
44+
45+ navigationController?.pushViewController(controller, animated: false)
46+ }
47+
48+}
GDproject/Controller/Log In/LogInViewController.swift+90−92
@@ -1,135 +1,128 @@
1//
1//
2// LogInViewController.swift
2// LogInViewController.swift
3−// RxSwift
3+// NewsFeed
4//
4//
5−// Created by cstore on 01/03/2019.
5+// Created by cstore on 20/01/2019.
6// Copyright © 2019 drHSE. All rights reserved.
6// Copyright © 2019 drHSE. All rights reserved.
7//
7//
8
8
9import UIKit
9import UIKit
10−import TinyConstraints
11−import ReactiveSwift
12−import ReactiveCocoa
13−import Result
14
10
15class LogInViewController: UIViewController {
11class LogInViewController: UIViewController {
16
12
17− var loading = UIActivityIndicatorView(style: .gray)
13+ @IBOutlet weak var mailTextField: UITextField!
18
14
19− var authenticate: ((String)->())?
15+ @IBOutlet weak var indicatorView: UIActivityIndicatorView!
20
16
21− func presentAlertInvalidCode()
17+ var onLogIn: ((Int)->())?
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
18
30− override func viewWillDisappear(_ animated: Bool) {
19+ var authenticateSucceeded: Bool? {
31− super.viewWillDisappear(animated)
20+ didSet {
32−
21+ if !authenticateSucceeded! {
33− loading.stopAnimating()
22+ indicatorView.stopAnimating()
23+ indicatorView.isHidden = true
24+ }
25+ }
34 }
26 }
35
27
36− let logInLabel: UILabel = {
28+ static let titleColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)
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
29
44− let mailTextField: UITextField = {
30+ var bottomConstraint: NSLayoutConstraint?
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
31
56 let logInButton: UIButton = {
32 let logInButton: UIButton = {
57 let button = UIButton(type: .system)
33 let button = UIButton(type: .system)
58 button.setTitle("Log In", for: .normal)
34 button.setTitle("Log In", for: .normal)
59− button.setTitleColor(blueSystemColor, for: .normal)
35+ button.setTitleColor(titleColor, for: .normal)
60 button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
36 button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
61− button.addTarget(self, action: #selector(handleTap), for: .touchUpInside)
62 button.isEnabled = false
37 button.isEnabled = false
38+ button.addTarget(self, action: #selector(activateLogInProcess), for: .touchUpInside)
63 return button
39 return button
64 }()
40 }()
65
41
66− @objc func handleTap(){
42+ let keyboardBar: UIView = {
67− loading.startAnimating()
43+ let view = UIView()
68− authenticate?(mailTextField.text!)
44+ view.backgroundColor = .white
45+ return view
46+ }()
47+
48+ override func viewDidLoad() {
49+ super.viewDidLoad()
50+ setUpView()
51+ configureTapgesture()
69 }
52 }
70
53
71− private lazy var keyboardBar = UIView()
54+ override func viewWillAppear(_ animated: Bool) {
72− private lazy var contentView = UIView()
55+ super.viewWillAppear(animated)
73− private var bottomConstraint: NSLayoutConstraint?
56+ }
74
57
75− func setUpView(){
58+ override func viewWillDisappear(_ animated: Bool) {
76− // logIn stack with textField and label
59+ super.viewWillDisappear(animated)
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 }
60 }
86
61
87− func configureKeyboard(){
62+ private func configureTapgesture(){
88−
63+ let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
89− mailTextField.keyboardType = .emailAddress
64+ view.addGestureRecognizer(tapGesture)
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 }
65 }
103
66
104− func logicOfLogInInputValidation() -> ((String?)->()) {
67+ @objc func handleTap(){
105−
68+ view.endEditing(true)
106− let logic: ((String?)->()) = { [weak self] (someText) in
69+ }
107− if let text = someText, !text.isEmpty, text.contains("@") {
70+
71+ @objc func activateLogInProcess(){
108− self?.logInButton.isEnabled = true
72+ if logInButton.isEnabled {
73+ // MARK:- when log in is succeeded do I need to go there?
74+ if let id = Int(mailTextField.text!){
75+ indicatorView.isHidden = false
76+ indicatorView.startAnimating()
77+ onLogIn?(id)
78+ view.endEditing(true)
109 } else {
79 } else {
110− self?.logInButton.isEnabled = false
80+ logInButton.isEnabled = false
81+ logInButton.setTitleColor(LogInViewController.titleColor.withAlphaComponent(0.5), for: .normal)
111 }
82 }
112 }
83 }
113−
114− return logic
115 }
84 }
116
85
117− override func viewDidLoad() {
86+ func setUpView(){
118− super.viewDidLoad()
87+ indicatorView.isHidden = true
119− self.view.backgroundColor = .white
88+ mailTextField.delegate = self
120− setUpView()
89+ view.addSubview(keyboardBar)
121− configureKeyboard()
122
90
123− let mailFieldValuesSignal: Signal<String, NoError> = mailTextField.reactive.continuousTextValues
91+ view.addConstraintsWithFormat(format: "H:|[v0]|", views: keyboardBar)
92+ view.addConstraintsWithFormat(format: "V:[v0(50)]", views: keyboardBar)
124
93
125− mailFieldValuesSignal.observeValues(logicOfLogInInputValidation())
94+ setUpBarComponents()
95+
96+ configureKeyboardBehavior()
97+ }
98+
99+ func configureKeyboardBehavior(){
100+ bottomConstraint = NSLayoutConstraint(item: keyboardBar, attribute: .bottom, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
101+ view.addConstraint(bottomConstraint!)
126
102
127 // for keyboard notifications
103 // for keyboard notifications
128 NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
104 NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
129
105
130 NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
106 NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
107+
108+ // for log in button notifications
109+ NotificationCenter.default.addObserver(self, selector: #selector(inputDidChanged), name: UITextField.textDidChangeNotification, object: mailTextField)
110+
111+ NotificationCenter.default.addObserver(self, selector: #selector(inputDidChanged), name: UITextField.textDidBeginEditingNotification, object: mailTextField)
131 }
112 }
132
113
114+ @objc func inputDidChanged(notification: NSNotification){
115+ if mailTextField.text?.isEmpty ?? true
116+ {
117+ logInButton.isEnabled = false
118+ logInButton.setTitleColor(LogInViewController.titleColor.withAlphaComponent(0.5), for: .normal)
119+ }
120+ else
121+ {
122+ logInButton.isEnabled = true
123+ logInButton.setTitleColor(LogInViewController.titleColor.withAlphaComponent(1), for: .normal)
124+ }
125+ }
133
126
134 @objc func handleKeyboardNotifications(notification: NSNotification){
127 @objc func handleKeyboardNotifications(notification: NSNotification){
135 if let userInfo = notification.userInfo{
128 if let userInfo = notification.userInfo{
@@ -143,13 +136,18 @@ class LogInViewController: UIViewController {
143 }
136 }
144 }
137 }
145
138
139+ func setUpBarComponents(){
140+ keyboardBar.addSubview(logInButton)
141+ keyboardBar.addConstraintsWithFormat(format: "H:[v0(60)]-16-|", views: logInButton)
142+ keyboardBar.addConstraintsWithFormat(format: "V:|[v0]|", views: logInButton)
143+ }
146}
144}
147
145
148−extension UIButton {
146+
149− override open var isEnabled: Bool {
147+extension LogInViewController: UITextFieldDelegate{
150− didSet {
148+ func textFieldShouldReturn(_ textField: UITextField) -> Bool
151− let color = isEnabled ? self.titleLabel?.textColor.withAlphaComponent(1) : self.titleLabel?.textColor.withAlphaComponent(0.5)
149+ {
152− self.setTitleColor(color, for: .normal)
150+ textField.resignFirstResponder()
153− }
151+ return true
154 }
152 }
155}
153}
GDproject/Controller/Log In/RegisterTableViewController.swiftdeleted−198
@@ -1,198 +0,0 @@
1−//
2−// RegisterTableViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 10/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class RegisterTableViewController: UITableViewController, ChosenFactulty
12−{
13−
14− func presentAlertInvalidData(message: String)
15− {
16− let alert = UIAlertController(title: "Invalid data", message: message, preferredStyle: .alert)
17− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
18− self.present(alert, animated: true, completion: nil)
19− }
20−
21− func onChooseFaculty(faculty: Model.Faculty) {
22− self.faculty = faculty
23− tableView.reloadData()
24− }
25−
26− weak var delegate: UpdateUser?
27−
28− var onRegistration: (()->())?
29−
30− var faculty: Model.Faculty?
31− var user: Model.NewRegistration = Model.NewRegistration(email: DataStorage.standard.getEmail()!, firstName: nil, middleName: nil, lastName: nil, faculty: nil)
32−
33− var userActive: Model.Users? {
34− didSet {
35− if let userA = userActive {
36− user.firstName = userA.firstName
37− user.middleName = userA.middleName
38− user.lastName = userA.lastName
39−
40− faculty = userA.faculty
41− self.updateUserIfCan = true
42− tableView.reloadData()
43− }
44− }
45− }
46−
47− var updateUserIfCan: Bool = false
48−
49− override func viewDidLoad()
50− {
51− super.viewDidLoad()
52−
53− navigationItem.largeTitleDisplayMode = .never
54− tableView.keyboardDismissMode = .interactive
55− navigationItem.title = user.email
56− navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(endRegistration))
57− }
58−
59−
60− @objc func endRegistration()
61− {
62− let fieldsMissing = "Some fields are missing. Add more information"
63− updateUser()
64− guard let faculty = faculty else { presentAlertInvalidData(message: fieldsMissing); return }
65−
66− user.faculty = faculty.url
67−
68− guard let name = user.firstName else { presentAlertInvalidData(message: fieldsMissing); return }
69− guard let middle = user.middleName else { presentAlertInvalidData(message: fieldsMissing); return }
70− guard let last = user.lastName else { presentAlertInvalidData(message: fieldsMissing); return }
71−
72− if updateUserIfCan {
73− guard let delegate = delegate else { return }
74− guard var userA = userActive else { return }
75−
76− // updating current
77− userA.firstName = name
78− userA.faculty = faculty
79− userA.middleName = middle
80− userA.lastName = last
81−
82− Model.userUpdate(with: user) { [weak self] in
83−
84− if $0 {
85− delegate.updateUserObj(with: userA)
86− self?.navigationController?.popViewController(animated: true)
87− } else {
88− self?.presentAlertInvalidData(message: "Something went wrong! Try again")
89− }
90−
91− }
92− } else {
93−
94− Model.register(object: user)
95− { [weak self] in
96− self?.onRegistration?()
97− }
98− }
99− }
100− // MARK: - Table view data source
101−
102− override func numberOfSections(in tableView: UITableView) -> Int {
103− return 2
104− }
105−
106− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
107−
108− switch section {
109− case 0:
110− return 3
111− default:
112− if let _ = faculty {
113− return 2
114− } else {
115− return 1
116− }
117− }
118− }
119−
120− override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
121− {
122− switch section {
123− case 0:
124− return "Initials"
125− default:
126− return "Faculty"
127− }
128− }
129−
130−
131− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
132− {
133− switch indexPath.section {
134− case 0:
135− let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! InititalsViewCell
136− switch indexPath.row{
137− case 0:
138− if let name = user.firstName {
139− cell.fill(with: name)
140− } else {
141− cell.initialsTextField.placeholder = "First name"
142− }
143− case 1:
144− if let name = user.middleName {
145− cell.fill(with: name)
146− } else {
147− cell.initialsTextField.placeholder = "Middle name"
148− }
149− default:
150− if let name = user.lastName {
151− cell.fill(with: name)
152− } else {
153− cell.initialsTextField.placeholder = "Last name"
154− }
155− }
156− cell.selectionStyle = .none
157− return cell
158− default:
159− switch indexPath.row {
160− case 0:
161− let cell = tableView.dequeueReusableCell(withIdentifier: "cell111", for: indexPath)
162− cell.selectionStyle = .none
163− return cell
164− default:
165− let cell = tableView.dequeueReusableCell(withIdentifier: "facultyCell", for: indexPath)
166− cell.textLabel?.text = faculty!.name
167− cell.detailTextLabel?.text = faculty!.campusName
168− cell.selectionStyle = .none
169− return cell
170− }
171− }
172− }
173−
174−
175− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
176− if indexPath.section == 1 && indexPath.row == 0 {
177−
178− updateUser()
179−
180− let vc = storyboard?.instantiateViewController(withIdentifier: "FacultyTableViewController") as! FacultyTableViewController
181−
182− vc.delegate = self
183−
184− self.navigationController?.pushViewController(vc, animated: true)
185− }
186− }
187−
188− func updateUser(){
189− guard let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as? InititalsViewCell else {return}
190− guard let cell1 = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? InititalsViewCell else {return}
191− guard let cell2 = tableView.cellForRow(at: IndexPath(row: 2, section: 0)) as? InititalsViewCell else {return}
192−
193− user.firstName = cell.initialsTextField.text!
194− user.middleName = cell1.initialsTextField.text!
195− user.lastName = cell2.initialsTextField.text!
196− }
197−
198−}
GDproject/Controller/Messages/ChatInfoViewController.swiftdeleted−308
@@ -1,308 +0,0 @@
1−//
2−// ChatInfoViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 02/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−/// Class for displaying chat info
12−///
13−class ChatInfoViewController: UITableViewController {
14−
15− enum PersonStatus{
16− case admin
17− case ordinary
18− }
19−
20− weak var delegate: UpdatableGroup?
21−
22− var groupChat: Model.Group? {
23− didSet{
24− if let groupChat = groupChat {
25− usersArray = groupChat.users.map { $0.key }
26− }
27− }
28− }
29−
30− var usersArray: [Int] = [] {
31− didSet {
32− tableView.reloadData()
33− }
34− }
35−
36− var users: [Int: Model.Users] = [:]
37−
38− func canIEditThisChat() -> PersonStatus
39− {
40− let myId = UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
41−
42− if let groupChatUserPermission = groupChat?.users[myId]?.isAdmin {
43− return groupChatUserPermission ? .admin : .ordinary
44− }
45−
46− return .ordinary
47− }
48−
49− var myPermissions: PersonStatus = .ordinary
50−
51−
52−
53− override func viewDidLoad() {
54− super.viewDidLoad()
55−
56− tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
57− myPermissions = canIEditThisChat()
58− tableView.reloadData()
59−
60− switch myPermissions {
61− case .admin:
62− navigationItem.rightBarButtonItem = self.editButtonItem
63− default:
64− return
65− }
66− }
67−
68− // MARK: - Table view data source
69−
70− override func numberOfSections(in tableView: UITableView) -> Int {
71− return 3
72− }
73−
74− override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
75− switch section {
76− case 0:
77− return 1
78− case 1:
79− return 1
80− default:
81− return usersArray.count + (myPermissions == .ordinary ? 0 : 1)
82− }
83− }
84−
85−
86− override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
87− {
88− let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
89−
90− if indexPath.row == 0 {
91− switch indexPath.section {
92− case 0:
93− cell.textLabel?.text = groupChat!.name
94− cell.selectionStyle = .none
95− return cell
96− case 1:
97− cell.textLabel?.text = "Leave chat"
98− cell.textLabel?.textColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
99− cell.selectionStyle = .none
100− return cell
101− default:
102− switch myPermissions{
103− case .admin:
104− cell.textLabel?.text = "Add participants"
105− cell.accessoryType = .disclosureIndicator
106− case .ordinary:
107− cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
108− }
109− cell.selectionStyle = .none
110− return cell
111− }
112− }
113−
114− switch myPermissions{
115− case .admin:
116− cell.textLabel?.text = name(for: users[usersArray[indexPath.row-1]])
117− case .ordinary:
118− cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
119− }
120− cell.selectionStyle = .none
121− return cell
122− }
123−
124− private func name(for user: Model.Users?) -> String {
125− if let user = user, let perm = groupChat?.users[user.id]?.isAdmin {
126− if perm {
127− return "🤴🏻 \(user.fullName())"
128− }
129− return "👤 \(user.fullName())"
130− }
131−
132− return "left"
133− }
134−
135− override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
136− {
137− switch section {
138− case 0:
139− return "Title"
140− case 1:
141− return "Opportunities"
142− default:
143− return "Participants"
144− }
145− }
146−
147−
148− func editName(for cell: UITableViewCell){
149− let alert = UIAlertController(title: "Are you sure?", message: "Title:", preferredStyle: .alert)
150−
151− let action1 = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
152−
153− alert.addTextField { [weak self] (tf) in
154− tf.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
155− tf.text = self?.groupChat?.name
156− }
157−
158− let action2 = UIAlertAction(title: "OK", style: .default) { [unowned self] _ in
159− let name = alert.textFields?.first?.text
160− cell.textLabel?.text = name
161− self.groupChat?.name = name!
162− Model.updateGroupChat(with: self.groupChat!)
163− self.delegate?.updateGroup(with: self.groupChat!)
164− }
165−
166− alert.addAction(action1)
167− alert.addAction(action2)
168−
169− present(alert, animated: true, completion: nil)
170− }
171− override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
172− {
173− guard let groupChat = groupChat else {
174− return
175− }
176−
177− guard let cell = tableView.cellForRow(at: indexPath) else {
178− return
179− }
180−
181− if indexPath.row == 0 {
182− switch indexPath.section{
183− case 0:
184− switch myPermissions{
185− case .admin:
186− editName(for: cell)
187− default:
188− break
189− }
190− case 1:
191− Model.leaveGroupChat(id: groupChat.id) {
192− [weak self] in
193− self?.navigationController?.popViewController(animated: true)
194− }
195− default:
196− switch myPermissions{
197− case .admin:
198− showUserChoiceVC()
199− default:
200− showParticipantPage(with: usersArray[indexPath.row])
201− }
202− }
203− }
204−
205−
206− if indexPath.section == 2 && indexPath.row != 0 {
207− switch myPermissions{
208− case .admin:
209− showParticipantPage(with: usersArray[indexPath.row-1])
210− default:
211− showParticipantPage(with: usersArray[indexPath.row])
212− }
213− }
214− }
215−
216− var onUserDiplay: ((Int)->())?
217−
218− func showParticipantPage(with user: Int?) {
219− if let user = user {
220− onUserDiplay?(user)
221− }
222− }
223−
224− func showUserChoiceVC()
225− {
226− let vc = storyboard?.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
227−
228− vc.whatToDoWithSelection = { [weak self, weak vc] mapa in
229−
230− mapa.forEach { self?.users[$0.key] = Model.Channels.fullPeopleDict[$0.key] }
231− mapa.forEach { self?.groupChat?.users[$0.key] = $0.value }
232− vc?.navigationController?.popViewController(animated: true)
233− }
234−
235− navigationController?.pushViewController(vc, animated: true)
236− }
237−
238− override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
239− {
240− if editingStyle == UITableViewCell.EditingStyle.delete {
241− groupChat?.users[usersArray[indexPath.row-1]] = nil
242− }
243−
244− tableView.reloadData()
245− }
246−
247− override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
248− if indexPath.row == 0 {
249− return false
250− }
251−
252− return true
253− }
254−
255− override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
256− {
257− let editButton = UITableViewRowAction(style: .normal, title: "Promote") { [unowned self] (rowAction, indexPath) in
258−
259− self.tableView.beginUpdates()
260− self.groupChat?.users[self.usersArray[indexPath.row-1]]?.isAdmin = true
261− self.tableView.reloadRows(at: [indexPath], with: .none)
262− self.tableView.endUpdates()
263− }
264−
265− editButton.backgroundColor = #colorLiteral(red: 0.476841867, green: 0.5048075914, blue: 1, alpha: 1)
266−
267− let restrictButton = UITableViewRowAction(style: .normal, title: "Restrict") { [unowned self] (rowAction, indexPath) in
268−
269− self.tableView.beginUpdates()
270− self.groupChat?.users[self.usersArray[indexPath.row-1]]?.isAdmin = false
271− self.tableView.reloadRows(at: [indexPath], with: .none)
272− self.tableView.endUpdates()
273− }
274−
275− restrictButton.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
276−
277− let deleteButton = UITableViewRowAction(style: .normal, title: "Delete") { [unowned self] (action, indexPath) in
278−
279− self.tableView.beginUpdates()
280− self.groupChat?.users[self.usersArray[indexPath.row-1]] = nil
281− self.tableView.deleteRows(at: [indexPath], with: .none)
282− self.tableView.endUpdates()
283− }
284−
285− deleteButton.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
286−
287− return [editButton, restrictButton, deleteButton]
288− }
289−
290− /// update chatInfo
291− override func viewWillDisappear(_ animated: Bool) {
292−
293− defer {
294− super.viewWillDisappear(animated)
295− }
296−
297− guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else {
298− switch myPermissions {
299− case .ordinary:
300− return
301− case .admin:
302− Model.updateGroupChat(with: groupChat!)
303− delegate?.updateGroup(with: groupChat!)
304− }
305− return
306− }
307− }
308−}
GDproject/Controller/Messages/Dialog/DialogCell.swiftdeleted−132
@@ -1,132 +0,0 @@
1−//
2−// DialogCell.swift
3−// GDproject
4−//
5−// Created by cstore on 05/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−import MarkdownKit
12−
13−class DialogCell: UITableViewCell {
14−
15− let nameLabel: UIButton = {
16− let button = UIButton()
17− button.setTitleColor(.black, for: .normal)
18− button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
19− button.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left
20− return button
21− }()
22−
23− @objc func displayProfile()
24− {
25− if let id = self.user?.id {
26− print("diplay")
27− onUserDisplay?(id)
28− }
29− }
30−
31− var onUserDisplay: ((Int)->())?
32−
33−
34− let timeLabel: UILabel = {
35− let label = UILabel()
36− label.font = UIFont.systemFont(ofSize: 9)
37− label.textAlignment = NSTextAlignment.right
38− label.textColor = #colorLiteral(red: 0.4352941176, green: 0.4431372549, blue: 0.4745098039, alpha: 1)
39− return label
40− }()
41−
42− func createTextView(with text: NSAttributedString, _ isSelectable: Bool) -> UITextView
43− {
44− let textView = UITextView()
45− textView.isScrollEnabled = false
46− textView.isEditable = false
47− textView.sizeToFit()
48−
49− if isSelectable {
50− textView.isSelectable = true
51− } else {
52− textView.isUserInteractionEnabled = false
53− }
54−
55− textView.attributedText = text
56− return textView
57− }
58−
59− override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
60− {
61− super.init(style: style, reuseIdentifier: reuseIdentifier)
62− }
63−
64− required init?(coder aDecoder: NSCoder)
65− {
66− fatalError("init(coder:) has not been implemented")
67− }
68−
69− var user: Model.Users? {
70− didSet{
71− nameLabel.setTitle(user!.fullName(), for: .normal)
72− }
73− }
74−
75− var textView: UITextView!
76−
77− func fill(with markdownText: NSAttributedString, byUser: Model.Users, when: String)
78− {
79− let myId = DataStorage.standard.getUserId()
80− // important
81− contentView.subviews.forEach({ $0.removeFromSuperview() })
82−
83− nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
84−
85− self.user = byUser
86− textView = createTextView(with: markdownText, true)
87− textView.layer.cornerRadius = 10
88− textView.clipsToBounds = true
89−
90− self.contentView.addSubview(textView)
91− self.contentView.addSubview(timeLabel)
92−
93− timeLabel.text = when.getDate()
94− textView.width(min: 50, max: self.contentView.bounds.width-70, priority: .required, isActive: true)
95−
96− if myId == byUser.id
97− {
98− layoutMyMessage()
99− } else {
100− layOutOtherMessage()
101− }
102− }
103−
104− func layOutOtherMessage(){
105− self.contentView.addSubview(nameLabel)
106−
107− nameLabel.setTitle(user!.fullName(), for: .normal)
108−
109− nameLabel.edgesToSuperview(excluding: .bottom, insets: .top(4) + .left(8))
110− textView.edgesToSuperview(excluding: [.top, .right] , insets: .left(8) + .bottom(20))
111− textView.topToBottom(of: nameLabel)
112−
113− textView.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
114− textView.textColor = .white
115− timeLabel.edgesToSuperview(excluding: .top, insets: .right(70) + .left(8))
116− timeLabel.topToBottom(of: textView, offset: 4)
117− timeLabel.textAlignment = .left
118− }
119−
120− func layoutMyMessage()
121− {
122− textView.edgesToSuperview(excluding: .left, insets: .right(8) + .bottom(20) + .top(4))
123− textView.backgroundColor = UIColor(red:0.08, green:0.49, blue:0.98, alpha:1.0)
124− textView.textColor = .white
125− timeLabel.edgesToSuperview(excluding: .top, insets: .left(70) + .right(8))
126− timeLabel.topToBottom(of: textView, offset: 4)
127− timeLabel.textAlignment = .right
128− }
129−}
130−
131−
132−
GDproject/Controller/Messages/Dialog/DialogViewController.swiftdeleted−340
@@ -1,340 +0,0 @@
1−//
2−// DialogViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 01/05/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−import TinyConstraints
11−import Marklight
12−
13−protocol UpdatableGroup:class {
14− func updateGroup(with group: Model.Group)
15−}
16−
17−class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegate, UITableViewDataSource
18−{
19− var onUserDisplay: ((Int)->())?
20−
21− var tableView: UITableView = UITableView()
22−
23− func updateGroup(with group: Model.Group){
24− self.groupChat?.group = group
25− setTitleForGroup(groupChat: groupChat!)
26− }
27−
28− let cellId = "cell3"
29− var onInfoShow: (()->())?
30−
31− var dialog: Model.Dialog? {
32− didSet{
33− switch dialog! {
34− case .groupChat(let chat):
35− self.groupChat = chat
36− case .userChat(let chat):
37− self.userChat = chat
38− }
39− }
40− }
41−
42− var groupChat: Model.GroupChat?
43− var userChat: Model.UserChat?
44−
45− var users: [Int: Model.Users]?
46−
47− var groupId: Int?
48−
49− var cellData: [PostCellData] = [] {
50− didSet {
51− tableView.reloadData()
52− canBePaginated = true
53− }
54− }
55−
56− override func viewDidLoad() {
57− super.viewDidLoad()
58−
59− setConstraints()
60− magicForKeyboardChanges()
61−
62− self.tableView.delegate = self
63− self.tableView.dataSource = self
64−
65− tableView.setContentOffset(CGPoint(x: 0, y: 50), animated: false)
66−
67− navigationItem.largeTitleDisplayMode = .never
68−
69− tableView.keyboardDismissMode = .onDrag
70− tableView.separatorStyle = .none
71− tableView.register(DialogCell.self, forCellReuseIdentifier: cellId)
72− tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
73− tableView.contentInsetAdjustmentBehavior = .never
74− tableView.contentOffset = CGPoint(x: 0, y: 30)
75−
76− if let groupChat = groupChat {
77− setTitleForGroup(groupChat: groupChat)
78− } else if let userChat = userChat{
79− setTitleForChat(userChat: userChat)
80− }
81− }
82−
83− var messageSendView: UIView = {
84− let view = UIView()
85− view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
86− return view
87− }()
88−
89− var messageTextView: UITextView =
90− {
91− let textStorage = MarklightTextStorage()
92− textStorage.marklightTextProcessor.codeColor = UIColor.orange
93− textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
94− textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
95− textStorage.marklightTextProcessor.codeFontName = "Courier"
96− textStorage.marklightTextProcessor.fontTextStyle = UIFont.TextStyle.subheadline.rawValue
97− textStorage.marklightTextProcessor.hideSyntax = false
98−
99− let layoutManager = NSLayoutManager()
100−
101− // Assign the `UITextView`'s `NSLayoutManager` to the `NSTextStorage` subclass
102− //textStorage.addLayoutManager(textView.layoutManager)
103− textStorage.addLayoutManager(layoutManager)
104−
105− let textContainer = NSTextContainer()
106− layoutManager.addTextContainer(textContainer)
107−
108− let textView = UITextView(frame: CGRect.zero, textContainer: textContainer)
109− textView.isEditable = true
110− textView.isScrollEnabled = true
111− textView.backgroundColor = .white
112− return textView
113− }()
114−
115− var sendButton: UIButton = {
116− let button = UIButton()
117− button.setTitle("Send", for: .normal)
118− button.setTitleColor(.blue, for: .normal)
119− button.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
120− button.addTarget(self, action: #selector(sendMessage), for: .touchUpInside)
121− return button
122− }()
123−
124− @objc func sendMessage()
125− {
126− var destination: Model.MessageDestination?
127−
128− if let group = groupChat {
129− destination = Model.MessageDestination.groupChatDestination(group.group.id)
130− } else if let user = userChat {
131− destination = Model.MessageDestination.userChatDestination(user.user)
132− }
133−
134− if let destination = destination
135− {
136− Model.sendMessage(message: Model.SendMessage(body: Model.Attachments(markdown: messageTextView.text), destination: destination)) { [unowned self] in
137−
138− switch $0 {
139− case .success, .success1:
140− self.getMessagesNew(for: self.dialog!)
141− self.messageTextView.text = ""
142− default:
143− self.showAlertOn(result: $0)
144− }
145− }
146−
147− prevLast = -1
148− }
149− }
150−
151− var lineView: UIView = {
152− let view = UIView()
153− view.backgroundColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
154− return view
155− }()
156−
157− var bottomConstraint: NSLayoutConstraint!
158−
159− func setConstraints(){
160− self.view.addSubview(tableView)
161− self.view.addSubview(messageSendView)
162−
163− messageSendView.addSubview(messageTextView)
164− messageSendView.addSubview(sendButton)
165− messageSendView.addSubview(lineView)
166−
167− messageSendView.edgesToSuperview(excluding: [.top,.bottom])
168−
169− bottomConstraint = NSLayoutConstraint(item: messageSendView, attribute: .bottom, relatedBy: .equal, toItem: self.view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
170− view.addConstraint(bottomConstraint)
171−
172− messageSendView.height(60)
173−
174− sendButton.edgesToSuperview(excluding: .left)
175− sendButton.width(60)
176−
177− lineView.edgesToSuperview(excluding: .bottom)
178− lineView.height(0.5)
179−
180− messageTextView.edgesToSuperview(excluding: .right)
181− messageTextView.rightToLeft(of: sendButton)
182−
183− tableView.edgesToSuperview(excluding: .bottom)
184− tableView.bottomToTop(of: messageSendView)
185−
186− self.view.layoutSubviews()
187− }
188−
189− func magicForKeyboardChanges()
190− {
191− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
192−
193− NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
194− }
195−
196− @objc func handleKeyboardNotifications(notification: NSNotification){
197− if let userInfo = notification.userInfo{
198− // UIKeyboardFrameEndUserInfoKey
199−
200− let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
201−
202− bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? -(keyBoardFrame.height) + self.view.safeAreaInsets.bottom : 0
203−
204− UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
205− self.view.layoutIfNeeded()
206− }) { (completed) in
207−
208− }
209− }
210− }
211−
212− func setTitleForChat(userChat: Model.UserChat){
213− navigationItem.title = "\(users![userChat.user]!.fullName())"
214− navigationItem.rightBarButtonItem = UIBarButtonItem(title: "👤", style: .plain, target: self, action: #selector(showPersonPage))
215− }
216−
217− @objc func showPersonPage(){
218− if let id = userChat?.user{
219− onUserDisplay?(id)
220− }
221− }
222−
223− func setTitleForGroup(groupChat: Model.GroupChat){
224− navigationItem.title = "\(groupChat.group.name)"
225− navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Info", style: .plain, target: self, action: #selector(moveToInfoVC))
226− }
227−
228− // onInfoShow
229− @objc func moveToInfoVC(){
230− let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: chatInfoViewController) as! ChatInfoViewController
231−
232− vc.delegate = self
233− vc.users = users!
234− vc.onUserDiplay = onUserDisplay
235−
236− if let groupChat = groupChat {
237− vc.groupChat = groupChat.group
238− }
239−
240− navigationController?.pushViewController(vc, animated: true)
241− }
242−
243− var currentMessagesInChat: [Model.LastMessage] = [] {
244− didSet
245− {
246− cellData = currentMessagesInChat.map { PostCellData(attributedData: PostCellData.create(with: [$0.body])) }
247− }
248− }
249−
250− // MARK: - Table view data source
251−
252− func numberOfSections(in tableView: UITableView) -> Int {
253− return 1
254− }
255−
256− func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
257− return cellData.count
258− }
259−
260− override func viewWillAppear(_ animated: Bool)
261− {
262− super.viewWillAppear(animated)
263− tabBarController?.tabBar.isHidden = true
264−
265− if let dialog = dialog {
266− getMessagesNew(for: dialog)
267− }
268− }
269−
270− func getMessages(for dialog: Model.Dialog, starting from: Int? = nil)
271− {
272− switch dialog {
273− case .groupChat(let groupChat):
274− Model.getMessagesFor(typeOfChat: Model.Dialog.groupChat(groupChat), chat: groupChat.group.id, exclusiveFrom: from)
275− { [weak self] in
276− self?.currentMessagesInChat.append(contentsOf: $0)
277− }
278− case .userChat(let userChat):
279− Model.getMessagesFor(typeOfChat: Model.Dialog.userChat(userChat), chat: userChat.user, exclusiveFrom: from)
280− { [weak self] in
281− self?.currentMessagesInChat.append(contentsOf: $0)
282− }
283− }
284− }
285−
286−
287− func getMessagesNew(for dialog: Model.Dialog, starting from: Int? = nil)
288− {
289− switch dialog {
290− case .groupChat(let groupChat):
291− Model.getMessagesFor(typeOfChat: Model.Dialog.groupChat(groupChat), chat: groupChat.group.id, exclusiveFrom: from)
292− { [weak self] in
293− self?.currentMessagesInChat = $0
294− }
295− case .userChat(let userChat):
296− Model.getMessagesFor(typeOfChat: Model.Dialog.userChat(userChat), chat: userChat.user, exclusiveFrom: from)
297− { [weak self] in
298− self?.currentMessagesInChat = $0
299− }
300− }
301− }
302−
303− func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
304− {
305− let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! DialogCell
306−
307− //In cellForRowAtIndexPath
308− cell.transform = CGAffineTransform(scaleX: 1, y: -1)
309− cell.selectionStyle = .none
310−
311−
312− if let user = users?[currentMessagesInChat[indexPath.row].author]
313− {
314− cell.fill(with: cellData[indexPath.row].attributedData, byUser: user, when: currentMessagesInChat[indexPath.row].time)
315−
316− cell.onUserDisplay = onUserDisplay
317− }
318−
319− return cell
320− }
321−
322− var prevLast = -1
323− var canBePaginated = false
324− func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
325− {
326− if indexPath.row == cellData.count - 1 && prevLast != indexPath.row && canBePaginated && cellData.count >= 24
327− {
328− print("exclusiveFrom \(currentMessagesInChat.last?.id ?? 0)")
329− if let dialog = dialog
330− {
331− getMessages(for: dialog, starting: currentMessagesInChat.last?.id)
332− }
333−
334− prevLast = indexPath.row
335− }
336− }
337−}
338−
339−
340−
GDproject/Controller/Messages/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+11−16
@@ -16,20 +16,17 @@ struct CellData{
16
16
17class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
17class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
18
18
19− var userInfo: Model.Users? {
19+ var dataSourse: [CellData] = [
20− didSet {
20+ CellData(opened: false, title: "Phone", sectionData: ["+7 901 733 01 79"]),
21− if let userInfo = userInfo {
22− dataSourse = [CellData(opened: false, title: "Contacts", sectionData: [userInfo.email, userInfo.faculty.address]),
21+ CellData(opened: false, title: "Mail", sectionData: ["vbogomazova@edu.hse.ru"]),
23− CellData(opened: false, title: "Faculty", sectionData: [userInfo.faculty.campusName, userInfo.faculty.name, userInfo.faculty.address, userInfo.faculty.path]),
22+ CellData(opened: false, title: "Research ID", sectionData: ["4567834336789456737"]),
23+ CellData(opened: false, title: "Published", sectionData: ["Это будет очень длинное название книги 1, чтобы сделать проверку", "Книга 2", "Книга 3"]),
24− CellData(opened: false, title: "Interests", sectionData: userInfo.faculty.tags)]
24+ CellData(opened: false, title: "Courses", sectionData: ["Курс 1", "Курс 2"]),
25− }
25+ CellData(opened: false, title: "Link", sectionData: ["https://wwww.hse.ru"])
26− }
26+ ]
27− }
28−
29− var dataSourse: [CellData] = [ ]
30
27
31 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
28 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
32− if (dataSourse[section].opened) {
29+ if (dataSourse[section].opened){
33 return dataSourse[section].sectionData.count + 1
30 return dataSourse[section].sectionData.count + 1
34 } else {
31 } else {
35 return 1
32 return 1
@@ -48,10 +45,8 @@ class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDat
48 cell.selectionStyle = .none
45 cell.selectionStyle = .none
49 return cell
46 return cell
50 } else {
47 } else {
51− let cell = tableView.dequeueReusableCell(withIdentifier: infoCellId, for: indexPath) as! InfoCell
48+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
52− cell.fill(title: dataSourse[indexPath.section].sectionData[indexPath.row - 1])
49+ cell.textLabel?.text = dataSourse[indexPath.section].sectionData[indexPath.row - 1]
53− cell.accessoryType = .none
54− cell.selectionStyle = .none
55 return cell
50 return cell
56 }
51 }
57 }
52 }
GDproject/Controller/Profile/InfoCell.swift+1−2
@@ -16,9 +16,8 @@ class InfoCell: UITableViewCell{
16 label.font = UIFont.systemFont(ofSize: 16)
16 label.font = UIFont.systemFont(ofSize: 16)
17 label.sizeToFit()
17 label.sizeToFit()
18 label.isScrollEnabled = false
18 label.isScrollEnabled = false
19− // label.isUserInteractionEnabled = false
19+ label.isUserInteractionEnabled = false
20 label.isEditable = false
20 label.isEditable = false
21− label.dataDetectorTypes = .all
22 label.textColor = .black
21 label.textColor = .black
23 return label
22 return label
24 }()
23 }()
GDproject/Controller/Profile/ProfileViewController.swift+66−148
@@ -9,17 +9,8 @@
9import UIKit
9import UIKit
10import TinyConstraints
10import TinyConstraints
11
11
12−protocol UpdateUser: class {
13− func updateUserObj(with user: Model.Users)
14−}
15−
16−class ProfileViewController: UIViewController, UpdateUser
12+class ProfileViewController: UIViewController
17{
13{
18− func updateUserObj(with user: Model.Users)
19− {
20− self.user = user
21− Model.Channels.fullPeopleDict[user.id] = user
22− }
23
14
24 @IBOutlet weak var segmentedControl: UISegmentedControl!
15 @IBOutlet weak var segmentedControl: UISegmentedControl!
25
16
@@ -39,34 +30,14 @@ class ProfileViewController: UIViewController, UpdateUser
39
30
40 @IBOutlet weak var newMessageButton: UIButton!
31 @IBOutlet weak var newMessageButton: UIButton!
41
32
42− var logOut: (()->())?
43−
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− }
58− }
59−
60− var protoDictionary: [String: UIImage] = ["135213": #imageLiteral(resourceName: "9"), "135288": #imageLiteral(resourceName: "5051"), "22723" : #imageLiteral(resourceName: "69"), "135083": #imageLiteral(resourceName: "42")]
61
33
62− func fill(with user: Model.Users)
34+ func fill(with user: Model.Users){
63− {
35+ self.facultyLabel.text = "Студент: Факультет Компьютерных Наук"
64− self.facultyLabel.text = user.faculty.name
65 self.nameLabel.text = "\(user.firstName) \(user.middleName)"
36 self.nameLabel.text = "\(user.firstName) \(user.middleName)"
66 self.surnameLabel.text = "\(user.lastName)"
37 self.surnameLabel.text = "\(user.lastName)"
67− self.profileImageView.image = protoDictionary[user.faculty.campusCode]?.roundedImage
38+ self.profileImageView.image = #imageLiteral(resourceName: "kitten").roundedImage
68− self.placeLabel.text = "📍\(user.faculty.address)"
39+ self.placeLabel.text = "📍Москва, Кочновский пр.3"
69− if user.id == DataStorage.standard.getUserId() {
40+ if user.id == DataStorage.standard.getUserId(){
70 newMessageButton.isHidden = true
41 newMessageButton.isHidden = true
71 } else {
42 } else {
72 newMessageButton.isHidden = false
43 newMessageButton.isHidden = false
@@ -75,61 +46,43 @@ class ProfileViewController: UIViewController, UpdateUser
75
46
76 var user: Model.Users? {
47 var user: Model.Users? {
77 didSet {
48 didSet {
78− if let user = user {
79− self.fill(with: user)
49+ self.fill(with: user!)
80− navigationItem.title = "\(user.firstName) \(user.lastName)"
50+ navigationItem.title = "\(user?.id ?? 0)"
81− } else if let id = idProfile {
82− Model.getUsers(for: [id]) { [unowned self ] in
83− self.user = $0[id]
84− }
85− }
86 }
51 }
87 }
52 }
88
53
89− var channel: Model.Channels? {
54+ var basicInfo = BasicInfoController()
90− didSet {
55+ var posts = NewsVC()
91− self.update()
92− }
93− }
94
56
95− func update()
57+ var dataSourse: [Model.Posts]?{
96− {
58+ didSet{
97− Model.getAnonymousChannel(by: channel!) { [unowned self] in
59+
98− self.posts.dataSourse = $0.posts
60+ var newPosts: [Model.Posts] = []
99− self.posts.dictionary = $0.users
61+
100− self.user = $0.users[self.idProfile!]
62+ dataSourse?.forEach({ (post) in
63+ newPosts.append(Model.Posts(body: post.body, authorId: post.authorId, id: post.id, user: user!, date: post.updated, tags: post.tags))
64+ })
65+
66+ self.posts.dataSourse = newPosts
67+ tableView.reloadData()
101 }
68 }
102 }
69 }
103
70
104− var basicInfo = BasicInfoController()
105− var posts = NewsVC()
106−
107 override func viewDidLoad()
71 override func viewDidLoad()
108 {
72 {
109 super.viewDidLoad()
73 super.viewDidLoad()
110− if idProfile == nil {
74+
111− idProfile = DataStorage.standard.getUserId()
75+
112− }
76+
113−
114 posts.viewController = self
77 posts.viewController = self
115 posts.type = .NONE
78 posts.type = .NONE
116− posts.currChannel = channel
117−
118− posts.onFullPost = {
119− [weak self] (type,post) in
120−
121− let vc = self?.storyboard?.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
122− vc.type = type
123− vc.post = post
124− self?.navigationController!.pushViewController(vc, animated: true)
125− }
126
79
127 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
80 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
128
81
129 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
82 tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
130
83
131 tableView.register(BasicInfoCell.self, forCellReuseIdentifier: basicInfoCellId)
84 tableView.register(BasicInfoCell.self, forCellReuseIdentifier: basicInfoCellId)
132−
85+
133 tableView.register(InfoCell.self, forCellReuseIdentifier: infoCellId)
86 tableView.register(InfoCell.self, forCellReuseIdentifier: infoCellId)
134
87
135 posts.viewController = self
88 posts.viewController = self
@@ -139,105 +92,71 @@ class ProfileViewController: UIViewController, UpdateUser
139 tableView.reloadData()
92 tableView.reloadData()
140 }
93 }
141
94
142− var idProfile: Int? {
95+ var idProfile: Int?
143− didSet {
144− channel = Model.Channels(people: [idProfile!], name: "", id: 0, tags: [])
145− }
146− }
147
96
148 override func viewWillAppear(_ animated: Bool) {
97 override func viewWillAppear(_ animated: Bool) {
149− tabBarController?.tabBar.isHidden = false
150−
151 if idProfile == nil {
98 if idProfile == nil {
152 idProfile = DataStorage.standard.getUserId()
99 idProfile = DataStorage.standard.getUserId()
153 }
100 }
154− user = Model.Channels.fullPeopleDict[idProfile!]
155
101
156− update()
102+ if let id = idProfile {
103+ if let user = Model.idUser[id] {
104+ self.user = user
105+ } else {
106+ Model.getUsers(for: [id]) { [weak self] (dic) in
107+ self?.user = dic[id]
108+ }
109+ }
110+
111+ Model.getPostsForUser(with: id) { [weak self] (posts) in
112+ self?.dataSourse = posts
113+ }
114+ }
157
115
158 setUpNavigarionBar()
116 setUpNavigarionBar()
159 }
117 }
160
118
161 func setUpNavigarionBar(){
119 func setUpNavigarionBar(){
162− // navigationController?.navigationBar.prefersLargeTitles = true
120+ navigationController?.navigationBar.prefersLargeTitles = true
121+ //navigationItem.title = "\(user?.id ?? 0)"
163 let uibarbutton = UIBarButtonItem(title: "More", style: .plain, target: self, action: #selector(showInformation))
122 let uibarbutton = UIBarButtonItem(title: "More", style: .plain, target: self, action: #selector(showInformation))
164 navigationItem.rightBarButtonItems = [uibarbutton]
123 navigationItem.rightBarButtonItems = [uibarbutton]
165 navigationItem.largeTitleDisplayMode = .always
124 navigationItem.largeTitleDisplayMode = .always
166 }
125 }
167
126
127+
128+ let copyLink: UIAlertAction = {
129+ let b = UIAlertAction(title: "Copy link", style: .default)
130+ return b
131+ }()
132+
168 @objc func showInformation(){
133 @objc func showInformation(){
169
134
135+ // drafts
136+ // saved
137+
170 let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
138 let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
139+ let editAction = UIAlertAction(title: "Edit profile", style: .default)
140+ let settingsAction = UIAlertAction(title: "Setting", style: .default)
141+ { [weak self] (_) in
142+
143+ let vc = self?.storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
144+ self?.navigationController?.pushViewController(vc, animated: true)
145+ }
171
146
172−
173 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
147 let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
174−
175−
176− if idProfile == DataStorage.standard.getUserId() {
177− let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
148+ let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
149+ {
178− { [weak self] (_) in
150+ (_) 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)
151+ DataStorage.standard.setIsLoggedIn(value: false, with: 0)
198− (UIApplication.shared.delegate as! AppDelegate).relaunch()
199− }
200− }
201− }
202−
203− let settingsAction = UIAlertAction(title: "Edit profile", style: .default)
204− { [weak self] (_) in
205−
206− if let settings = self?.onSettings{
207− settings()
208− } else {
209− let vc = self?.storyboard?.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
210− vc.delegate = self
211− vc.userActive = self?.user
212−
213− self?.navigationController?.pushViewController(vc, animated: true)
214− }
215− }
216−
217− optionMenu.addAction(settingsAction)
218− optionMenu.addAction(logoutAction)
219− optionMenu.addAction(deleetAllSessionsAction)
220− } else {
221− let channelAction = UIAlertAction(title: "Add to a channel", style: .default)
222− {
223− [weak self] (_) in
224−
225− let vc = self?.storyboard?.instantiateViewController(withIdentifier: simplifiedChannelsList) as! SimplifiedChannelsList
226− vc.user = self?.user
227−
228− let transition = CATransition()
229− transition.duration = 0.5
230− transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
231− transition.type = CATransitionType.moveIn
232− transition.subtype = CATransitionSubtype.fromTop
233− self?.navigationController?.view.layer.add(transition, forKey: nil)
234− self?.navigationController?.pushViewController(vc, animated: false)
235− }
236−
237− optionMenu.addAction(channelAction)
238 }
152 }
239
153
154+ optionMenu.addAction(editAction)
155+ optionMenu.addAction(settingsAction)
156+ optionMenu.addAction(copyLink)
157+ optionMenu.addAction(logoutAction)
240 optionMenu.addAction(cancelAction)
158 optionMenu.addAction(cancelAction)
159+
241 self.present(optionMenu, animated: true, completion: nil)
160 self.present(optionMenu, animated: true, completion: nil)
242 }
161 }
243
162
@@ -267,7 +186,6 @@ class ProfileViewController: UIViewController, UpdateUser
267 func changeToBasicInfo(){
186 func changeToBasicInfo(){
268 tableView.delegate = basicInfo
187 tableView.delegate = basicInfo
269 tableView.dataSource = basicInfo
188 tableView.dataSource = basicInfo
270− basicInfo.userInfo = self.user
271 tableView.reloadData()
189 tableView.reloadData()
272 }
190 }
273}
191}
GDproject/Controller/RepeatingTimer.swiftnew file+59
@@ -0,0 +1,59 @@
1+/// RepeatingTimer mimics the API of DispatchSourceTimer but in a way that prevents
2+/// crashes that occur from calling resume multiple times on a timer that is
3+/// already resumed (noted by https://github.com/SiftScience/sift-ios/issues/52
4+
5+import Foundation
6+
7+class RepeatingTimer {
8+
9+ let timeInterval: TimeInterval
10+
11+ init(timeInterval: TimeInterval) {
12+ self.timeInterval = timeInterval
13+ }
14+
15+ private lazy var timer: DispatchSourceTimer = {
16+ let t = DispatchSource.makeTimerSource()
17+ t.schedule(deadline: .now() + self.timeInterval, repeating: self.timeInterval)
18+ t.setEventHandler(handler: { [weak self] in
19+ self?.eventHandler?()
20+ })
21+ return t
22+ }()
23+
24+ var eventHandler: (() -> Void)?
25+
26+ private enum State {
27+ case suspended
28+ case resumed
29+ }
30+
31+ private var state: State = .suspended
32+
33+ deinit {
34+ timer.setEventHandler {}
35+ timer.cancel()
36+ /*
37+ If the timer is suspended, calling cancel without resuming
38+ triggers a crash. This is documented here https://forums.developer.apple.com/thread/15902
39+ */
40+ resume()
41+ eventHandler = nil
42+ }
43+
44+ func resume() {
45+ if state == .resumed {
46+ return
47+ }
48+ state = .resumed
49+ timer.resume()
50+ }
51+
52+ func suspend() {
53+ if state == .suspended {
54+ return
55+ }
56+ state = .suspended
57+ timer.suspend()
58+ }
59+}
GDproject/DataStorage.swift+9−9
@@ -37,17 +37,18 @@ class DataStorage{
37 return UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
37 return UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
38 }
38 }
39
39
40− func setEmail(email: String) {
41− UserDefaults.standard.set(email, forKey: UserDefaultsKeys.email.rawValue)
42− }
43−
44− func getEmail() -> String? {
45− return UserDefaults.standard.string(forKey: UserDefaultsKeys.email.rawValue)
46− }
47 /**
40 /**
48 Function to determine is user logged in already or not
41 Function to determine is user logged in already or not
49 */
42 */
50− var isLoggedIn: Bool = UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue)
43+ var isLoggedIn: Bool = UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue) {
44+ didSet{
45+ if isLoggedIn && getUserId() != 0 {
46+ (UIApplication.shared.delegate as? AppDelegate)?.tabCoordinator.start()
47+ } else {
48+ (UIApplication.shared.delegate as? AppDelegate)?.logInAgain()
49+ }
50+ }
51+ }
51}
52}
52
53
53/**
54/**
@@ -56,5 +57,4 @@ class DataStorage{
56enum UserDefaultsKeys: String{
57enum UserDefaultsKeys: String{
57 case loggedIn
58 case loggedIn
58 case id
59 case id
59− case email
60}
60}
GDproject/Extentions.swift−47
@@ -60,50 +60,3 @@ extension UIStoryboard {
60 return UIStoryboard.userEdit.instantiateViewController(withIdentifier: logInController) as! LogInViewController
60 return UIStoryboard.userEdit.instantiateViewController(withIdentifier: logInController) as! LogInViewController
61 }
61 }
62}
62}
63−
64−
65−extension String {
66− func getDate() -> String
67− {
68− let dateFormatter = DateFormatter()
69− dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"//this your string date format
70− dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
71− let date = dateFormatter.date(from: self)
72−
73− dateFormatter.dateFormat = "MMM d, yyyy HH:mm" ///this is what you want to convert format
74− dateFormatter.timeZone = NSTimeZone.local
75− let timeStamp = dateFormatter.string(from: date!)
76−
77− return timeStamp
78− }
79−}
80−
81−extension UIViewController {
82− func showAlertOn(result: ResultR) {
83−
84− let message: String
85−
86− switch result {
87− case .impossibleContent:
88− message = "Impossible content"
89− case .exceededContent:
90− message = "The content exceeded"
91− case .longContent:
92− message = "The content is too long"
93− case .badAccess:
94− message = "Try reloading the page again"
95− case .alreadyRegistered:
96− message = "User is already registered"
97− case .tooMuchToAdd:
98− message = "Limit of channels exceeded"
99− case .success, .success1:
100− return
101− default:
102− message = "Something went wrong"
103− }
104−
105− let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
106− alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
107− self.present(alert, animated: true, completion: nil)
108− }
109−}
GDproject/Simple model/CompletionTree.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.swift+64−847
@@ -7,85 +7,40 @@
7//
7//
8
8
9import Foundation
9import Foundation
10−import UIKit
11import Alamofire
10import Alamofire
12
11
13−enum ResultR: Int {
14− case internalServerError = 500
15− case exceededContent = 470
16− case longContent = 471
17− case incorrectContent = 472
18− case impossibleContent = 473
19− case invalidTocken = 498
20− case alreadyRegistered = 409
21− case invalidCode = 403
22− case badAccess = 400
23− case tooMuchToAdd = 406
24− case notFound = 404
25− case success1 = 204
26− case success = 200
27−}
28−
29class Model{
12class Model{
30
13
31 static let invalidTocken = 498
14 static let invalidTocken = 498
32
15
33− static var hashTagTree: CompletionTree?
34−
35− private static var isValidTocken: ((Int)->())? = { responce in
16+ private static var isValidTocken: ((Int)->())? = {
17+ responce in
36− print(responce)
18+ print("\(responce)")
37 if responce == invalidTocken {
19 if responce == invalidTocken {
38−
39 DataStorage.standard.setIsLoggedIn(value: false, with: 0)
20 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 }
21 }
46 }
22 }
47
23
48 private static let baseUrl = "https://valera-denis.herokuapp.com"
24 private static let baseUrl = "https://valera-denis.herokuapp.com"
49 static let decoder = JSONDecoder()
25 static let decoder = JSONDecoder()
50−
26+
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")!
27+ static let url = URL(string:"\(baseUrl)/authentication/login")!
56− static let logOutURL = URL(string:"\(baseUrl)/authentication/logout")!
57− static let postsLastURL = URL(string:"\(baseUrl)/posts/last")!
28+ static let url1 = URL(string:"\(baseUrl)/posts/last")!
58− static let postsForUserURL = URL(string:"\(baseUrl)/posts/forUser")!
29+ static let urlForPostsForUser = URL(string:"\(baseUrl)/posts/forUser")!
30+ static let urlForUsers = URL(string:"\(baseUrl)/users")!
59− static let postsPublishURL = URL(string:"\(baseUrl)/posts/publish")!
31+ static let createAndPublishURL = 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")!
32 static let channelsGetURL = URL(string: "\(baseUrl)/channels/get")!
64 static let channelsUpdateURL = URL(string: "\(baseUrl)/channels/update")!
33 static let channelsUpdateURL = URL(string: "\(baseUrl)/channels/update")!
65 static let channelsListURL = URL(string: "\(baseUrl)/channels")!
34 static let channelsListURL = URL(string: "\(baseUrl)/channels")!
66 static let channelsCreateURL = URL(string: "\(baseUrl)/channels/create")!
35 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
36
81
37
82− struct QueryPosts<T: Codable>: Codable {
38+ struct QueryPosts: Codable{
83 var users: [Int: Users]
39 var users: [Int: Users]
84− var response: [T]
40+ var posts: [Posts]
85 }
41 }
86
42
87 struct Posts: Codable {
43 struct Posts: Codable {
88−
89 var body: [Attachments]
44 var body: [Attachments]
90 var authorId: Int
45 var authorId: Int
91 var id: Int
46 var id: Int
@@ -148,12 +103,7 @@ class Model{
148 var lastName: String
103 var lastName: String
149 var firstName: String
104 var firstName: String
150 var id: Int
105 var id: Int
151− var faculty: Faculty
152− var email: String
153
106
154− func fullName() -> String {
155− return "\(firstName) \(lastName)"
156− }
157 }
107 }
158
108
159 struct Attachments: Codable {
109 struct Attachments: Codable {
@@ -175,15 +125,18 @@ class Model{
175
125
176 struct Channels: Codable {
126 struct Channels: Codable {
177
127
178− // static var fullTags = Set<String>()
179− static var fullPeople = [Users]()
180− static var fullPeopleDict = [Int:Users]()
181−
182 var people: [Int]
128 var people: [Int]
183 var name: String
129 var name: String
184 var id: Int?
130 var id: Int?
185 var tags: [String]
131 var tags: [String]
186
132
133+ enum CodingKeys: String, CodingKey {
134+ case people
135+ case name
136+ case id
137+ case tags
138+ }
139+
187 init(people: [Int], name: String, id: Int, tags: [String]) {
140 init(people: [Int], name: String, id: Int, tags: [String]) {
188 self.id = id
141 self.id = id
189 self.people = people
142 self.people = people
@@ -197,124 +150,34 @@ class Model{
197 self.name = name
150 self.name = name
198 }
151 }
199
152
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 {
153 func encode(to encoder: Encoder) throws {
208 var container = encoder.container(keyedBy: CodingKeys.self)
154 var container = encoder.container(keyedBy: CodingKeys.self)
209 try container.encode(people, forKey: .people)
155 try container.encode(people, forKey: .people)
210 try container.encode(name, forKey: .name)
156 try container.encode(name, forKey: .name)
211− try container.encode(id, forKey: .id)
157+ // try container.encode(id, forKey: .id)
212 try container.encode(tags, forKey: .tags)
158 try container.encode(tags, forKey: .tags)
213 }
159 }
214− }
215−
216− struct AuthStatus: Codable {
217− var userStatus: String
218
160
219− init(){
220− userStatus = "invalid"
221− }
222 }
161 }
223
162
224− static func logout(completion: @escaping (()->())){
163+ static func authenticate(with id: Int, completion: @escaping ((Bool)->())) {
225− var request = URLRequest(url: logOutURL)
226− request.httpMethod = "POST"
227
164
228− AF.request(request).response { (responce) in
165+ let json: [String:Any] = ["authenticationId" : id]
229− isValidTocken?(responce.response?.statusCode ?? 498)
166+ let jsonData = try? JSONSerialization.data(withJSONObject: json)
230−
231− if let code = responce.response?.statusCode, code == 498 {
232− return
233− }
234−
235− completion()
236− }
237− }
238−
239− /*
240− "email": "vchernyshev@hse.ru",
241− "middleName": "Algebrovich",
242− "lastName": "Leonidov",
243− "faculty": "cs.hse.ru/dse",
244− "firstName": "Seva"
245− */
246−
247− struct NewRegistration: Codable{
248− var email: String
249− var firstName: String?
250− var middleName: String?
251− var lastName: String?
252− var faculty: String?
253− }
254−
255− static func register(object: NewRegistration, completion: @escaping (()->())) {
256− var request = URLRequest(url: registerMeURL)
257− request.httpBody = try? JSONEncoder().encode(object)
258
167
168+ var request = URLRequest(url: url)
259 request.httpMethod = "POST"
169 request.httpMethod = "POST"
260− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
261
170
262− AF.request(request).response { (responce) in
171+ // insert json data to the request
263−
264− guard let code = responce.response?.statusCode else { return }
265− isValidTocken?(code)
266−
267− if let code = responce.response?.statusCode, code == 498 {
268− return
269− }
270−
271− if code == 204 {
272−
273− let fields = responce.response?.allHeaderFields as? [String :String]
274− let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields!, for: responce.response!.url!)
275− HTTPCookieStorage.shared.setCookie(cookies[0])
276−
277− completion()
278− }
279− }
280− }
281−
282− // true only if everything is good
283− static func verify(with code: Int, completion: @escaping ((Bool)->())){
284− var request = URLRequest(url: authVerifyURL)
285− request.httpMethod = "POST"
286− request.httpBody = "\(code)".data(using: .utf8)
172+ request.httpBody = jsonData
287 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
173 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
288
174
289 AF.request(request).response { (responce) in
175 AF.request(request).response { (responce) in
290
176
291− guard let statusCode = responce.response?.statusCode else { completion(false); return }
177+ guard let realResponse = responce.response, realResponse.statusCode == 200 else
292− isValidTocken?(statusCode)
178+ {
293−
179+ print("Not a 200 response")
294− if let code = responce.response?.statusCode, code == 498 {
295− return
296− }
297−
298− if statusCode == 204 {
299− // at this point cookies are set
300− completion(true)
301− } else {
302 completion(false)
180 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
181 return
319 }
182 }
320
183
@@ -324,87 +187,26 @@ class Model{
324 return
187 return
325 }
188 }
326
189
327− DataStorage.standard.setIsLoggedIn(value: true, with: personId)
190+ let fields = realResponse.allHeaderFields as? [String :String]
328− completion(true)
329− }
330− }
331−
332− // register, ok or invalid
333− static func authenticate(with email: String, completion: @escaping ((AuthStatus)->())) {
334−
335− let json: [String:Any] = ["authenticationEmail" : email]
336− let jsonData = try? JSONSerialization.data(withJSONObject: json)
337−
338− var request = URLRequest(url: authenticationURL)
339− request.httpMethod = "POST"
340−
341− // insert json data to the request
342− request.httpBody = jsonData
343− request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
344−
345− AF.request(request).response { (response) in
346
191
347− guard let realResponse = response.response, realResponse.statusCode == 200 else
192+ let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields!, for: realResponse.url!)
348− {
349− print("Not a 200 response")
350− completion(AuthStatus())
351− return
352− }
353−
354− guard let json = response.data else { return }
355− guard let res = try? decoder.decode(AuthStatus.self, from: json) else { return }
356
193
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])
194+ HTTPCookieStorage.shared.setCookie(cookies[0])
363− }
364
195
196+ DataStorage.standard.setIsLoggedIn(value: true, with: personId)
365− completion(res)
197+ completion(true)
366 }
198 }
367 }
199 }
368
200
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
201
399− static func getLast(on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
202+ static func getLast(completion: @escaping (((users:[Int: Users], posts:[Posts]))->())){
400− {
203+ let jsonString = "30"
401− let postRequest = GeneralRequest<[Int]>(limit: limit, exclusiveFrom: pointInTime, request: [])
204+ var request = URLRequest(url: url1)
402
205
403− var request = URLRequest(url: postsLastURL)
404− request.httpBody = try? JSONEncoder().encode(postRequest)
405 request.httpMethod = "POST"
206 request.httpMethod = "POST"
406
207
407 // insert json data to the request
208 // insert json data to the request
209+ request.httpBody = jsonString.data(using: .utf8)
408 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
210 request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
409
211
410 AF.request(request).responseJSON {
212 AF.request(request).responseJSON {
@@ -412,24 +214,20 @@ class Model{
412
214
413 isValidTocken?(response.response?.statusCode ?? 498)
215 isValidTocken?(response.response?.statusCode ?? 498)
414
216
415− if let code = response.response?.statusCode, code == 498 {
416− return
417− }
418−
419 guard let json = response.data else { return }
217 guard let json = response.data else { return }
420
218
421− guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { print("no")
219+ guard let newQueery = try? decoder.decode(QueryPosts.self, from: json) else { print("no")
422 return }
220 return }
423
221
424 idUser = newQueery.users
222 idUser = newQueery.users
425− completion((newQueery.users, newQueery.response))
223+ completion((newQueery.users, newQueery.posts))
426 }
224 }
427 }
225 }
428
226
429
227
430− static func createAndPublish(body: [Attachments], tags: [String], completion: @escaping ((ResultR)->())){
228+ static func createAndPublish(body: [Attachments], tags: [String]){
431 let jsonUpd = CreatedPost(body: body, tags: tags)
229 let jsonUpd = CreatedPost(body: body, tags: tags)
432− var request = URLRequest(url: postsPublishURL)
230+ var request = URLRequest(url: createAndPublishURL)
433
231
434 request.httpMethod = "POST"
232 request.httpMethod = "POST"
435
233
@@ -441,32 +239,19 @@ class Model{
441 (response) in
239 (response) in
442
240
443 isValidTocken?(response.response?.statusCode ?? 498)
241 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 }
242 }
457 }
243 }
458
244
459−// static func requestForPosts(limit: Int = 10, ){
460−//
461−// }
462
245
463− static func getPostsForUser(for limit: Int = 10, from pointInTime: Int? = nil, with id: Int, completion: @escaping (([Posts])->()))
246+ static func getPostsForUser(with id: Int, completion: @escaping (([Posts])->())){
464− {
247+ let json = [
465− let postsRequest = GeneralRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: id)
248+ "request" : id,
249+ "limit": 10
250+ ]
466
251
467− let jsonData = try? JSONEncoder().encode(postsRequest)
252+ let jsonData = try? JSONSerialization.data(withJSONObject: json)
468
253
469− var request = URLRequest(url: postsForUserURL)
254+ var request = URLRequest(url: urlForPostsForUser)
470 request.httpMethod = "POST"
255 request.httpMethod = "POST"
471
256
472 // insert json data to the request
257 // insert json data to the request
@@ -478,15 +263,11 @@ class Model{
478
263
479 isValidTocken?(response.response?.statusCode ?? 498)
264 isValidTocken?(response.response?.statusCode ?? 498)
480
265
481− if let code = response.response?.statusCode, code == 498 {
482− return
483− }
484−
485 guard let json = response.data else { return }
266 guard let json = response.data else { return }
486
267
487− guard let newPost = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
268+ guard let newPost = try? decoder.decode(QueryPosts.self, from: json) else { return }
488
269
489− completion(newPost.response)
270+ completion(newPost.posts)
490 }
271 }
491 }
272 }
492
273
@@ -494,8 +275,8 @@ class Model{
494
275
495 static func getUsers(for ids: [Int], completion: @escaping (([Int:Users])->())){
276 static func getUsers(for ids: [Int], completion: @escaping (([Int:Users])->())){
496 let json = "\(Set(ids))"
277 let json = "\(Set(ids))"
497−
278+ print(json)
498− var request = URLRequest(url: usersURL)
279+ var request = URLRequest(url: urlForUsers)
499
280
500 request.httpMethod = "POST"
281 request.httpMethod = "POST"
501
282
@@ -508,29 +289,26 @@ class Model{
508
289
509 isValidTocken?(response.response?.statusCode ?? 498)
290 isValidTocken?(response.response?.statusCode ?? 498)
510
291
511− if let code = response.response?.statusCode, code == 498 {
512− return
513− }
514−
515 guard let json = response.data else { return }
292 guard let json = response.data else { return }
516
293
517 guard let users = try? decoder.decode([Users].self, from: json) else { return }
294 guard let users = try? decoder.decode([Users].self, from: json) else { return }
518
295
519− var dict: [Int:Users] = [:]
520−
521 users.forEach({ (user) in
296 users.forEach({ (user) in
522− dict[user.id] = user
297+ Model.idUser[user.id] = user
523 })
298 })
524
299
525− completion(dict)
300+ completion(Model.idUser)
526 }
301 }
527 }
302 }
528
303
529 // get channel (with id): in responce -- PostQuery
304 // 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]))->()))
305+ static func getChannel(with channelId: Int, completion: @escaping (((users:[Int: Users], posts:[Posts]))->())){
531− {
306+ let json = [
532− let postRequest = GeneralRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: channelId)
307+ "request" : channelId,
533− let jsonData = try? JSONEncoder().encode(postRequest)
308+ "limit": 10
309+ ]
310+
311+ let jsonData = try? JSONSerialization.data(withJSONObject: json)
534
312
535 var request = URLRequest(url: channelsGetURL)
313 var request = URLRequest(url: channelsGetURL)
536 request.httpMethod = "POST"
314 request.httpMethod = "POST"
@@ -544,21 +322,18 @@ class Model{
544
322
545 isValidTocken?(response.response?.statusCode ?? 498)
323 isValidTocken?(response.response?.statusCode ?? 498)
546
324
547− if let code = response.response?.statusCode, code == 498 {
548− return
549− }
550
325
551 guard let json = response.data else { return }
326 guard let json = response.data else { return }
552
327
553− guard let newQueery = try? decoder.decode(QueryPosts<Posts>.self, from: json) else { return }
328+ guard let newQueery = try? decoder.decode(QueryPosts.self, from: json) else { return }
554
329
555 idUser = newQueery.users
330 idUser = newQueery.users
556− completion((newQueery.users, newQueery.response))
331+ completion((newQueery.users, newQueery.posts))
557 }
332 }
558 }
333 }
559
334
560
335
561− static func createChannel(with channel: Channels, completion: @escaping ((ResultR)->())) {
336+ static func createChannel(with channel: Channels) {
562
337
563 var request = URLRequest(url: channelsCreateURL)
338 var request = URLRequest(url: channelsCreateURL)
564 request.httpMethod = "POST"
339 request.httpMethod = "POST"
@@ -569,13 +344,6 @@ class Model{
569 (response) in
344 (response) in
570
345
571 isValidTocken?(response.response?.statusCode ?? 498)
346 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 }
347 }
580
348
581 }
349 }
@@ -588,9 +356,6 @@ class Model{
588 AF.request(request).responseJSON { (response) in
356 AF.request(request).responseJSON { (response) in
589
357
590 isValidTocken?(response.response?.statusCode ?? 498)
358 isValidTocken?(response.response?.statusCode ?? 498)
591− if let code = response.response?.statusCode, code == 498 {
592− return
593− }
594
359
595 guard let json = response.data else { return }
360 guard let json = response.data else { return }
596
361
@@ -599,552 +364,4 @@ class Model{
599 completion(channelsList)
364 completion(channelsList)
600 }
365 }
601 }
366 }
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}
367}
GDproject/Simple model/Post.swift+26
@@ -9,6 +9,31 @@
9import Foundation
9import Foundation
10import UIKit
10import UIKit
11
11
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+
12enum Media{
37enum Media{
13 case text(String)
38 case text(String)
14 case image([UIImage])
39 case image([UIImage])
@@ -16,6 +41,7 @@ enum Media{
16}
41}
17
42
18struct Comment {
43struct Comment {
44+ var from: User
19 var atTime: String
45 var atTime: String
20 var withData: String
46 var withData: String
21}
47}
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+42−13
@@ -12,28 +12,57 @@ import UIKit
12class AppDelegate: UIResponder, UIApplicationDelegate {
12class AppDelegate: UIResponder, UIApplicationDelegate {
13
13
14
14
15+ var coordinator: LogInCoordinator!
16+ var tabCoordinator: TabbarCoordinator!
17+
15 var window: UIWindow?
18 var window: UIWindow?
16− var appCoordinator: ApplicationCoordinator!
19+ var rootController: UINavigationController? {
20+ return self.window!.rootViewController as? UINavigationController
21+ }
22+
23+ func logInAgain(){
24+ let root = UIStoryboard.navRoot()
25+ window?.rootViewController = root
26+ window?.makeKeyAndVisible()
27+ coordinator = LogInCoordinator(navigationController: root, window: UIApplication.shared.keyWindow!)
28+ coordinator!.start()
29+ }
17
30
18
31
19 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
32 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
20 {
33 {
21− window = UIWindow(frame: UIScreen.main.bounds)
34+ coordinator = LogInCoordinator(navigationController: rootController!, window: window!)
22− window?.makeKeyAndVisible()
35+ tabCoordinator = TabbarCoordinator(window: window!)
23−
36+ // TODO:- determine what to do here: log in or tabbar
24− // window?.rootViewController = UINavigationController()
37+ if DataStorage.standard.isLoggedIn {
25− Model.getCompl { (complTree) in
38+ tabCoordinator.start()
26− Model.hashTagTree = complTree
39+ } else {
40+ coordinator.start()
27 }
41 }
28
42
29− appCoordinator = ApplicationCoordinator(window: window!)
30− appCoordinator.start()
31−
32 return true
43 return true
33 }
44 }
34−
45+
35− func relaunch(){
46+ func applicationWillResignActive(_ application: UIApplication) {
36− appCoordinator.start()
47+ // 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.
48+ // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
49+ }
50+
51+ func applicationDidEnterBackground(_ application: UIApplication) {
52+ // 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.
53+ // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
54+ }
55+
56+ func applicationWillEnterForeground(_ application: UIApplication) {
57+ // 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.
58+ }
59+
60+ func applicationDidBecomeActive(_ application: UIApplication) {
61+ // 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.
62+ }
63+
64+ func applicationWillTerminate(_ application: UIApplication) {
65+ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
37 }
66 }
38}
67}
39
68
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/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.