Merge pull request #19 from dashared/developer

Developer
This commit is contained in:
Darya Rednikina 2019-05-20 00:30:01 +03:00 committed by GitHub
commit 2d942f3ce6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 4900 additions and 980 deletions

View File

@ -2,6 +2,8 @@ github "robb/Cartography"
github "ivanbruel/MarkdownKit"
github "roberthein/TinyConstraints"
github "macteo/Marklight"
github "ElaWorkshop/TagListView"
github "Alamofire/Alamofire" "5.0.0-beta.2"
github "whitesmith/WSTagsField"
github "Alamofire/Alamofire" "5.0.0-beta.5"
github "52inc/Pulley"
github "HeroTransitions/Hero"
github "ReactiveCocoa/ReactiveCocoa" ~> 9.0
github "ZaidSA/TaggerKit" "bb826a7"

View File

@ -8,21 +8,36 @@
/* Begin PBXBuildFile section */
1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */; };
123AD0E3223C1C3900326173 /* WSTagsField.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 123AD0E2223C1C3900326173 /* WSTagsField.framework */; };
123AD0E5223C1C4300326173 /* WSTagsField.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 123AD0E2223C1C3900326173 /* WSTagsField.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
121A8972226B1EAC005EE599 /* TagsSuggestionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */; };
1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */; };
123589FD22899339002F8028 /* MessageViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123589FC22899339002F8028 /* MessageViewCell.swift */; };
123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
124CC7032221C00C009DF531 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124CC7022221C00C009DF531 /* Model.swift */; };
124CC7052221C2BB009DF531 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 124CC7042221C2BA009DF531 /* Alamofire.framework */; };
124CC7072221C2C3009DF531 /* Alamofire.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 124CC7042221C2BA009DF531 /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1253867D2223DC9F00CC5EA7 /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1253867C2223DC9F00CC5EA7 /* RepeatingTimer.swift */; };
125A9A8A2285C3DA00513E2A /* CodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A892285C3DA00513E2A /* CodeViewController.swift */; };
125A9A8E2286068A00513E2A /* RegisterTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */; };
125A9A90228609C500513E2A /* InititalsViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A8F228609C500513E2A /* InititalsViewCell.swift */; };
125A9A922286100800513E2A /* FacultyTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125A9A912286100800513E2A /* FacultyTableViewController.swift */; };
125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57C22171D2A008A3575 /* ProfileViewController.swift */; };
125BD57F22171D73008A3575 /* Extentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD57E22171D73008A3575 /* Extentions.swift */; };
125BD5812217314A008A3575 /* NewsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125BD5802217314A008A3575 /* NewsVC.swift */; };
1261BB93227B364C003898CF /* ChannelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB92227B364C003898CF /* ChannelViewController.swift */; };
1261BB95227B3991003898CF /* AddToChannelVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB94227B3991003898CF /* AddToChannelVC.swift */; };
1261BB9E227B793D003898CF /* ChatInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1261BB9D227B793D003898CF /* ChatInfoViewController.swift */; };
12758257227F1401001F291F /* DialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12758256227F1401001F291F /* DialogViewController.swift */; };
1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1288B5CD221F1158002BE6B1 /* DataStorage.swift */; };
1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */; };
1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE332221569B009D3F23 /* TabbarCoordinator.swift */; };
1291BE3622218DBF009D3F23 /* LogInCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1291BE3522218DBF009D3F23 /* LogInCoordinator.swift */; };
129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320032279B4270035C7B3 /* MessagesViewController.swift */; };
129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320062279B5690035C7B3 /* MessagesCoordinator.swift */; };
129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */; };
1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1293200C2279D7310035C7B3 /* CompletionTree.swift */; };
1298810B227F13840032ACA3 /* DialogCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1298810A227F13840032ACA3 /* DialogCell.swift */; };
12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */; };
12BA4B9D224101E700DF93D7 /* BaseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */; };
12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */; };
12CE7D6F227B94B10024B6E8 /* TaggerKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */; };
12CE7D71227B94B50024B6E8 /* TaggerKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12D7D133221C321600B35452 /* ChannelListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D132221C321600B35452 /* ChannelListController.swift */; };
12D7D135221C42B700B35452 /* ChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D134221C42B700B35452 /* ChannelController.swift */; };
12D7D137221D78E800B35452 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D7D136221D78E800B35452 /* Channel.swift */; };
@ -36,39 +51,54 @@
12E36DA1221424EA006FCDD7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36D9F221424EA006FCDD7 /* Main.storyboard */; };
12E36DA3221424ED006FCDD7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA2221424ED006FCDD7 /* Assets.xcassets */; };
12E36DA6221424ED006FCDD7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA4221424ED006FCDD7 /* LaunchScreen.storyboard */; };
12E36DAF22143D40006FCDD7 /* Cartography.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DAE22143D40006FCDD7 /* Cartography.framework */; };
12E36DB322143D4E006FCDD7 /* Marklight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB222143D4E006FCDD7 /* Marklight.framework */; };
12E36DB522143D54006FCDD7 /* TinyConstraints.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */; };
12E36DB72214400A006FCDD7 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB62214400A006FCDD7 /* Post.swift */; };
12E36DB922144016006FCDD7 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB822144016006FCDD7 /* User.swift */; };
12E36DBD221441D5006FCDD7 /* TinyConstraints.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12E36DC0221441DB006FCDD7 /* Marklight.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB222143D4E006FCDD7 /* Marklight.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12E36DC2221441E1006FCDD7 /* MarkdownKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12E36DC4221441EA006FCDD7 /* Cartography.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DAE22143D40006FCDD7 /* Cartography.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DC922144635006FCDD7 /* NewPostViewController.swift */; };
12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCB22144725006FCDD7 /* PostViewCell.swift */; };
12E36DCE22144756006FCDD7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCD22144756006FCDD7 /* Constants.swift */; };
12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DD022148122006FCDD7 /* FullPostController.swift */; };
12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DD422156559006FCDD7 /* MyStackView.swift */; };
12E36DD8221594A9006FCDD7 /* TagListView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DD622159493006FCDD7 /* TagListView.framework */; };
12E36DD9221594A9006FCDD7 /* TagListView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DD622159493006FCDD7 /* TagListView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12E36DDB221594B1006FCDD7 /* MarkdownKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */; };
12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F3D6AF224106F700A69214 /* TabbarController.swift */; };
12F3D6B22241097B00A69214 /* ProfileCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12F3D6B12241097B00A69214 /* ProfileCoordinator.swift */; };
12FDAC7C226B5E2900995B4E /* Marklight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC75226B5E2800995B4E /* Marklight.framework */; };
12FDAC7D226B5E2900995B4E /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC76226B5E2800995B4E /* Result.framework */; };
12FDAC7E226B5E2900995B4E /* Cartography.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC77226B5E2900995B4E /* Cartography.framework */; };
12FDAC81226B5E2900995B4E /* MarkdownKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */; };
12FDAC84226B5E3700995B4E /* Alamofire.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC79226B5E2900995B4E /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC88226B5E4800995B4E /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC79226B5E2900995B4E /* Alamofire.framework */; };
12FDAC8A226B5E4B00995B4E /* Cartography.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC77226B5E2900995B4E /* Cartography.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC8B226B5E4E00995B4E /* Hero.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC78226B5E2900995B4E /* Hero.framework */; };
12FDAC8C226B5E4E00995B4E /* Hero.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC78226B5E2900995B4E /* Hero.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC8E226B5E5000995B4E /* MarkdownKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC90226B5E5200995B4E /* Marklight.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC75226B5E2800995B4E /* Marklight.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC91226B5E5400995B4E /* Pulley.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC7B226B5E2900995B4E /* Pulley.framework */; };
12FDAC92226B5E5400995B4E /* Pulley.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC7B226B5E2900995B4E /* Pulley.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC94226B5E5600995B4E /* Result.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC76226B5E2800995B4E /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC96226B61C400995B4E /* TinyConstraints.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC95226B61C400995B4E /* TinyConstraints.framework */; };
12FDAC98226B61CB00995B4E /* TinyConstraints.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC95226B61C400995B4E /* TinyConstraints.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC9B226B652C00995B4E /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC99226B652400995B4E /* ReactiveSwift.framework */; };
12FDAC9C226B652C00995B4E /* ReactiveSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC99226B652400995B4E /* ReactiveSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12FDAC9F226B9E7C00995B4E /* ReactiveCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */; };
12FDACA0226B9E7C00995B4E /* ReactiveCocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
12E36DBE221441D5006FCDD7 /* Embed Frameworks */ = {
12FDAC85226B5E3700995B4E /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
12E36DC0221441DB006FCDD7 /* Marklight.framework in Embed Frameworks */,
124CC7072221C2C3009DF531 /* Alamofire.framework in Embed Frameworks */,
12E36DC4221441EA006FCDD7 /* Cartography.framework in Embed Frameworks */,
12E36DD9221594A9006FCDD7 /* TagListView.framework in Embed Frameworks */,
12E36DBD221441D5006FCDD7 /* TinyConstraints.framework in Embed Frameworks */,
123AD0E5223C1C4300326173 /* WSTagsField.framework in Embed Frameworks */,
12E36DC2221441E1006FCDD7 /* MarkdownKit.framework in Embed Frameworks */,
12FDAC8E226B5E5000995B4E /* MarkdownKit.framework in Embed Frameworks */,
12FDAC98226B61CB00995B4E /* TinyConstraints.framework in Embed Frameworks */,
12FDAC94226B5E5600995B4E /* Result.framework in Embed Frameworks */,
12FDAC84226B5E3700995B4E /* Alamofire.framework in Embed Frameworks */,
12FDAC8A226B5E4B00995B4E /* Cartography.framework in Embed Frameworks */,
12FDAC9C226B652C00995B4E /* ReactiveSwift.framework in Embed Frameworks */,
12FDAC92226B5E5400995B4E /* Pulley.framework in Embed Frameworks */,
12FDAC8C226B5E4E00995B4E /* Hero.framework in Embed Frameworks */,
12FDAC90226B5E5200995B4E /* Marklight.framework in Embed Frameworks */,
12CE7D71227B94B50024B6E8 /* TaggerKit.framework in Embed Frameworks */,
12FDACA0226B9E7C00995B4E /* ReactiveCocoa.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@ -77,19 +107,35 @@
/* Begin PBXFileReference section */
1210A0BA223940310080686D /* SimplifiedChannelsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplifiedChannelsList.swift; sourceTree = "<group>"; };
123AD0E2223C1C3900326173 /* WSTagsField.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WSTagsField.framework; path = Carthage/Build/iOS/WSTagsField.framework; sourceTree = "<group>"; };
121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsSuggestionController.swift; sourceTree = "<group>"; };
1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaggsSelectionViewController.swift; sourceTree = "<group>"; };
123589FC22899339002F8028 /* MessageViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewCell.swift; sourceTree = "<group>"; };
123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
123E37A6221F1DD700F6E42A /* MainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
124CC7022221C00C009DF531 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
124CC7042221C2BA009DF531 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = "<group>"; };
1253867C2223DC9F00CC5EA7 /* RepeatingTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer.swift; sourceTree = "<group>"; };
125A9A892285C3DA00513E2A /* CodeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeViewController.swift; sourceTree = "<group>"; };
125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterTableViewController.swift; sourceTree = "<group>"; };
125A9A8F228609C500513E2A /* InititalsViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InititalsViewCell.swift; sourceTree = "<group>"; };
125A9A912286100800513E2A /* FacultyTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FacultyTableViewController.swift; sourceTree = "<group>"; };
125BD57C22171D2A008A3575 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = "<group>"; };
125BD57E22171D73008A3575 /* Extentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extentions.swift; sourceTree = "<group>"; };
125BD5802217314A008A3575 /* NewsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsVC.swift; sourceTree = "<group>"; };
1261BB92227B364C003898CF /* ChannelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelViewController.swift; sourceTree = "<group>"; };
1261BB94227B3991003898CF /* AddToChannelVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddToChannelVC.swift; sourceTree = "<group>"; };
1261BB9D227B793D003898CF /* ChatInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoViewController.swift; sourceTree = "<group>"; };
12758256227F1401001F291F /* DialogViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DialogViewController.swift; sourceTree = "<group>"; };
1288B5CD221F1158002BE6B1 /* DataStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStorage.swift; sourceTree = "<group>"; };
1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelsCoordinator.swift; sourceTree = "<group>"; };
1291BE332221569B009D3F23 /* TabbarCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbarCoordinator.swift; sourceTree = "<group>"; };
1291BE3522218DBF009D3F23 /* LogInCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInCoordinator.swift; sourceTree = "<group>"; };
129320032279B4270035C7B3 /* MessagesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = "<group>"; };
129320062279B5690035C7B3 /* MessagesCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesCoordinator.swift; sourceTree = "<group>"; };
129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PeopleToWriteViewController.swift; path = GDproject/Controller/Messages/PeopleToWriteViewController.swift; sourceTree = SOURCE_ROOT; };
1293200C2279D7310035C7B3 /* CompletionTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionTree.swift; sourceTree = "<group>"; };
1298810A227F13840032ACA3 /* DialogCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialogCell.swift; sourceTree = "<group>"; };
12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationCoordinator.swift; sourceTree = "<group>"; };
12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCoordinator.swift; sourceTree = "<group>"; };
12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInCoordinator.swift; sourceTree = "<group>"; };
12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TaggerKit.framework; path = Carthage/Build/iOS/TaggerKit.framework; sourceTree = "<group>"; };
12D7D132221C321600B35452 /* ChannelListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelListController.swift; sourceTree = "<group>"; };
12D7D134221C42B700B35452 /* ChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelController.swift; sourceTree = "<group>"; };
12D7D136221D78E800B35452 /* Channel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channel.swift; sourceTree = "<group>"; };
@ -105,18 +151,24 @@
12E36DA2221424ED006FCDD7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
12E36DA5221424ED006FCDD7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
12E36DA7221424ED006FCDD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
12E36DAE22143D40006FCDD7 /* Cartography.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cartography.framework; path = Carthage/Build/iOS/Cartography.framework; sourceTree = "<group>"; };
12E36DB022143D47006FCDD7 /* MarkdownKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MarkdownKit.framework; path = Carthage/Build/iOS/MarkdownKit.framework; sourceTree = "<group>"; };
12E36DB222143D4E006FCDD7 /* Marklight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Marklight.framework; path = Carthage/Build/iOS/Marklight.framework; sourceTree = "<group>"; };
12E36DB422143D54006FCDD7 /* TinyConstraints.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TinyConstraints.framework; path = Carthage/Build/iOS/TinyConstraints.framework; sourceTree = "<group>"; };
12E36DB62214400A006FCDD7 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
12E36DB822144016006FCDD7 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
12E36DC922144635006FCDD7 /* NewPostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPostViewController.swift; sourceTree = "<group>"; };
12E36DCB22144725006FCDD7 /* PostViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewCell.swift; sourceTree = "<group>"; };
12E36DCD22144756006FCDD7 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
12E36DD022148122006FCDD7 /* FullPostController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullPostController.swift; sourceTree = "<group>"; };
12E36DD422156559006FCDD7 /* MyStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyStackView.swift; sourceTree = "<group>"; };
12E36DD622159493006FCDD7 /* TagListView.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TagListView.framework; path = Carthage/Build/iOS/TagListView.framework; sourceTree = "<group>"; };
12F3D6AF224106F700A69214 /* TabbarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbarController.swift; sourceTree = "<group>"; };
12F3D6B12241097B00A69214 /* ProfileCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileCoordinator.swift; sourceTree = "<group>"; };
12FDAC75226B5E2800995B4E /* Marklight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Marklight.framework; path = Carthage/Build/iOS/Marklight.framework; sourceTree = "<group>"; };
12FDAC76226B5E2800995B4E /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = "<group>"; };
12FDAC77226B5E2900995B4E /* Cartography.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cartography.framework; path = Carthage/Build/iOS/Cartography.framework; sourceTree = "<group>"; };
12FDAC78226B5E2900995B4E /* Hero.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Hero.framework; path = Carthage/Build/iOS/Hero.framework; sourceTree = "<group>"; };
12FDAC79226B5E2900995B4E /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = "<group>"; };
12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MarkdownKit.framework; path = Carthage/Build/iOS/MarkdownKit.framework; sourceTree = "<group>"; };
12FDAC7B226B5E2900995B4E /* Pulley.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pulley.framework; path = Carthage/Build/iOS/Pulley.framework; sourceTree = "<group>"; };
12FDAC95226B61C400995B4E /* TinyConstraints.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TinyConstraints.framework; path = Carthage/Build/iOS/TinyConstraints.framework; sourceTree = "<group>"; };
12FDAC99226B652400995B4E /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = "<group>"; };
12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveCocoa.framework; path = Carthage/Build/iOS/ReactiveCocoa.framework; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -124,13 +176,17 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
12E36DB522143D54006FCDD7 /* TinyConstraints.framework in Frameworks */,
124CC7052221C2BB009DF531 /* Alamofire.framework in Frameworks */,
12E36DDB221594B1006FCDD7 /* MarkdownKit.framework in Frameworks */,
12E36DD8221594A9006FCDD7 /* TagListView.framework in Frameworks */,
12E36DAF22143D40006FCDD7 /* Cartography.framework in Frameworks */,
123AD0E3223C1C3900326173 /* WSTagsField.framework in Frameworks */,
12E36DB322143D4E006FCDD7 /* Marklight.framework in Frameworks */,
12FDAC7C226B5E2900995B4E /* Marklight.framework in Frameworks */,
12FDAC96226B61C400995B4E /* TinyConstraints.framework in Frameworks */,
12FDAC91226B5E5400995B4E /* Pulley.framework in Frameworks */,
12FDAC9F226B9E7C00995B4E /* ReactiveCocoa.framework in Frameworks */,
12FDAC88226B5E4800995B4E /* Alamofire.framework in Frameworks */,
12FDAC81226B5E2900995B4E /* MarkdownKit.framework in Frameworks */,
12FDAC7D226B5E2900995B4E /* Result.framework in Frameworks */,
12FDAC9B226B652C00995B4E /* ReactiveSwift.framework in Frameworks */,
12FDAC7E226B5E2900995B4E /* Cartography.framework in Frameworks */,
12CE7D6F227B94B10024B6E8 /* TaggerKit.framework in Frameworks */,
12FDAC8B226B5E4E00995B4E /* Hero.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -150,33 +206,68 @@
path = Profile;
sourceTree = "<group>";
};
1291BE32222154C3009D3F23 /* Coordinator tab bar? */ = {
1291BE32222154C3009D3F23 /* Coordinators */ = {
isa = PBXGroup;
children = (
12BA4B9A224101A400DF93D7 /* ApplicationCoordinator.swift */,
129320062279B5690035C7B3 /* MessagesCoordinator.swift */,
12F3D6AF224106F700A69214 /* TabbarController.swift */,
12F3D6B12241097B00A69214 /* ProfileCoordinator.swift */,
12BA4B9E224102B700DF93D7 /* LogInCoordinator.swift */,
12BA4B9C224101E700DF93D7 /* BaseCoordinator.swift */,
1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */,
1291BE332221569B009D3F23 /* TabbarCoordinator.swift */,
);
path = "Coordinator tab bar?";
path = Coordinators;
sourceTree = "<group>";
};
1291BE3722218DC4009D3F23 /* Log In */ = {
isa = PBXGroup;
children = (
125A9A912286100800513E2A /* FacultyTableViewController.swift */,
125A9A8F228609C500513E2A /* InititalsViewCell.swift */,
125A9A8D2286068A00513E2A /* RegisterTableViewController.swift */,
125A9A892285C3DA00513E2A /* CodeViewController.swift */,
123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
1291BE3522218DBF009D3F23 /* LogInCoordinator.swift */,
);
path = "Log In";
sourceTree = "<group>";
};
129320052279B4300035C7B3 /* Messages */ = {
isa = PBXGroup;
children = (
1261BB9D227B793D003898CF /* ChatInfoViewController.swift */,
129320082279C3B50035C7B3 /* PeopleToWriteViewController.swift */,
1298810C227F138C0032ACA3 /* Dialog */,
129320032279B4270035C7B3 /* MessagesViewController.swift */,
123589FC22899339002F8028 /* MessageViewCell.swift */,
);
path = Messages;
sourceTree = "<group>";
};
1298810C227F138C0032ACA3 /* Dialog */ = {
isa = PBXGroup;
children = (
12758256227F1401001F291F /* DialogViewController.swift */,
1298810A227F13840032ACA3 /* DialogCell.swift */,
);
path = Dialog;
sourceTree = "<group>";
};
12E36D8F221424EA006FCDD7 = {
isa = PBXGroup;
children = (
123AD0E2223C1C3900326173 /* WSTagsField.framework */,
124CC7042221C2BA009DF531 /* Alamofire.framework */,
12E36DD622159493006FCDD7 /* TagListView.framework */,
12E36DB422143D54006FCDD7 /* TinyConstraints.framework */,
12E36DB222143D4E006FCDD7 /* Marklight.framework */,
12E36DB022143D47006FCDD7 /* MarkdownKit.framework */,
12E36DAE22143D40006FCDD7 /* Cartography.framework */,
12CE7D6E227B94B00024B6E8 /* TaggerKit.framework */,
12FDAC9D226B9E7600995B4E /* ReactiveCocoa.framework */,
12FDAC99226B652400995B4E /* ReactiveSwift.framework */,
12FDAC95226B61C400995B4E /* TinyConstraints.framework */,
12FDAC79226B5E2900995B4E /* Alamofire.framework */,
12FDAC77226B5E2900995B4E /* Cartography.framework */,
12FDAC78226B5E2900995B4E /* Hero.framework */,
12FDAC7A226B5E2900995B4E /* MarkdownKit.framework */,
12FDAC75226B5E2800995B4E /* Marklight.framework */,
12FDAC7B226B5E2900995B4E /* Pulley.framework */,
12FDAC76226B5E2800995B4E /* Result.framework */,
12E36D9A221424EA006FCDD7 /* GDproject */,
12E36D99221424EA006FCDD7 /* Products */,
12E36DDA221594B1006FCDD7 /* Frameworks */,
@ -212,9 +303,9 @@
isa = PBXGroup;
children = (
124CC7022221C00C009DF531 /* Model.swift */,
1293200C2279D7310035C7B3 /* CompletionTree.swift */,
12E36DB62214400A006FCDD7 /* Post.swift */,
12D7D136221D78E800B35452 /* Channel.swift */,
12E36DB822144016006FCDD7 /* User.swift */,
);
path = "Simple model";
sourceTree = "<group>";
@ -232,8 +323,8 @@
12E36DCF22145923006FCDD7 /* Controller */ = {
isa = PBXGroup;
children = (
1253867C2223DC9F00CC5EA7 /* RepeatingTimer.swift */,
1291BE32222154C3009D3F23 /* Coordinator tab bar? */,
1291BE32222154C3009D3F23 /* Coordinators */,
129320052279B4300035C7B3 /* Messages */,
1291BE3722218DC4009D3F23 /* Log In */,
1288B5CC221F0EFE002BE6B1 /* Profile */,
12E36DD322156519006FCDD7 /* News and channels */,
@ -244,13 +335,16 @@
12E36DD322156519006FCDD7 /* News and channels */ = {
isa = PBXGroup;
children = (
1261BB92227B364C003898CF /* ChannelViewController.swift */,
1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */,
1261BB94227B3991003898CF /* AddToChannelVC.swift */,
12D7D134221C42B700B35452 /* ChannelController.swift */,
121A8971226B1EAC005EE599 /* TagsSuggestionController.swift */,
12D7D132221C321600B35452 /* ChannelListController.swift */,
1210A0BA223940310080686D /* SimplifiedChannelsList.swift */,
12E36DC922144635006FCDD7 /* NewPostViewController.swift */,
12E36DD022148122006FCDD7 /* FullPostController.swift */,
12E36D9D221424EA006FCDD7 /* NewsController.swift */,
1291BE2C2221312C009D3F23 /* ChannelsCoordinator.swift */,
125BD5802217314A008A3575 /* NewsVC.swift */,
12E36DCB22144725006FCDD7 /* PostViewCell.swift */,
);
@ -274,7 +368,7 @@
12E36D94221424EA006FCDD7 /* Sources */,
12E36D95221424EA006FCDD7 /* Frameworks */,
12E36D96221424EA006FCDD7 /* Resources */,
12E36DBE221441D5006FCDD7 /* Embed Frameworks */,
12FDAC85226B5E3700995B4E /* Embed Frameworks */,
);
buildRules = (
);
@ -297,6 +391,11 @@
TargetAttributes = {
12E36D97221424EA006FCDD7 = {
CreatedOnToolsVersion = 10.1;
SystemCapabilities = {
com.apple.Keychain = {
enabled = 0;
};
};
};
};
};
@ -336,31 +435,49 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */,
124CC7032221C00C009DF531 /* Model.swift in Sources */,
125A9A90228609C500513E2A /* InititalsViewCell.swift in Sources */,
1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */,
12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */,
12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
12D7D137221D78E800B35452 /* Channel.swift in Sources */,
1291BE3622218DBF009D3F23 /* LogInCoordinator.swift in Sources */,
12E36DB922144016006FCDD7 /* User.swift in Sources */,
1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */,
125BD5812217314A008A3575 /* NewsVC.swift in Sources */,
12E36DB72214400A006FCDD7 /* Post.swift in Sources */,
12DB7FDF221877160096878E /* InviteViewController.swift in Sources */,
121A8972226B1EAC005EE599 /* TagsSuggestionController.swift in Sources */,
1293200D2279D7310035C7B3 /* CompletionTree.swift in Sources */,
12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */,
1261BB9E227B793D003898CF /* ChatInfoViewController.swift in Sources */,
12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */,
1298810B227F13840032ACA3 /* DialogCell.swift in Sources */,
125A9A922286100800513E2A /* FacultyTableViewController.swift in Sources */,
125A9A8E2286068A00513E2A /* RegisterTableViewController.swift in Sources */,
123589FD22899339002F8028 /* MessageViewCell.swift in Sources */,
12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */,
123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */,
125BD57F22171D73008A3575 /* Extentions.swift in Sources */,
12D7D133221C321600B35452 /* ChannelListController.swift in Sources */,
125A9A8A2285C3DA00513E2A /* CodeViewController.swift in Sources */,
1291BE342221569B009D3F23 /* TabbarCoordinator.swift in Sources */,
129320092279C3B50035C7B3 /* PeopleToWriteViewController.swift in Sources */,
12BA4B9B224101A400DF93D7 /* ApplicationCoordinator.swift in Sources */,
1291BE2D2221312D009D3F23 /* ChannelsCoordinator.swift in Sources */,
12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */,
129320042279B4270035C7B3 /* MessagesViewController.swift in Sources */,
12758257227F1401001F291F /* DialogViewController.swift in Sources */,
1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */,
12BA4B9F224102B700DF93D7 /* LogInCoordinator.swift in Sources */,
12F3D6B22241097B00A69214 /* ProfileCoordinator.swift in Sources */,
125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */,
1253867D2223DC9F00CC5EA7 /* RepeatingTimer.swift in Sources */,
1261BB95227B3991003898CF /* AddToChannelVC.swift in Sources */,
12DB7FDB2218590C0096878E /* InfoCell.swift in Sources */,
12DB7FD922181E660096878E /* BasicInfoCell.swift in Sources */,
1261BB93227B364C003898CF /* ChannelViewController.swift in Sources */,
12D7D135221C42B700B35452 /* ChannelController.swift in Sources */,
12E36D9C221424EA006FCDD7 /* AppDelegate.swift in Sources */,
12BA4B9D224101E700DF93D7 /* BaseCoordinator.swift in Sources */,
12DB7FD722181CD20096878E /* BasicInfoController.swift in Sources */,
12E36DCE22144756006FCDD7 /* Constants.swift in Sources */,
12DB7FDD221872F80096878E /* SettingsViewController.swift in Sources */,
@ -510,6 +627,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 9Z6LFGKA9G;
FRAMEWORK_SEARCH_PATHS = (
@ -521,9 +639,10 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject;
PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject.sos;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
@ -532,6 +651,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 9Z6LFGKA9G;
FRAMEWORK_SEARCH_PATHS = (
@ -543,9 +663,10 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject;
PRODUCT_BUNDLE_IDENTIFIER = rednikina.com.drHSE.GDproject.sos;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;

View File

@ -1,16 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<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">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="Stack View standard spacing" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Chats-->
<scene sceneID="bZ2-fw-XBE">
<objects>
<navigationController id="gt4-mD-66Q" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Chats" image="chat" id="ZPm-j1-3dy"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="XiY-wd-750">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4yT-77-90q" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1089" y="481"/>
</scene>
<!--Profile View Controller-->
<scene sceneID="rQ6-TM-V7T">
<objects>
@ -20,7 +34,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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">
<rect key="frame" x="0.0" y="116" width="375" height="502"/>
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<view key="tableHeaderView" contentMode="scaleToFill" id="kFZ-3c-OFY">
<rect key="frame" x="0.0" y="0.0" width="375" height="199"/>
@ -76,6 +90,9 @@
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yir-N6-Q6f">
<rect key="frame" x="246" y="0.0" width="97" height="30"/>
<state key="normal" title="New message"/>
<connections>
<action selector="sendMessage:" destination="R4D-Ao-uvG" eventType="touchUpInside" id="tQc-5f-SU3"/>
</connections>
</button>
</subviews>
</stackView>
@ -131,7 +148,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="sap-zV-B7l" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2013.5999999999999" y="957.57121439280365"/>
<point key="canvasLocation" x="1884" y="1216"/>
</scene>
<!--Settings View Controller-->
<scene sceneID="WVn-Qy-9tO">
@ -168,7 +185,7 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="xdg-ZK-4Jv" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1986" y="1756"/>
<point key="canvasLocation" x="1980" y="1979"/>
</scene>
<!--Invite View Controller-->
<scene sceneID="DcO-6Y-Iko">
@ -212,7 +229,251 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="t8a-Sv-mbh" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2803" y="1756"/>
<point key="canvasLocation" x="2799" y="1979"/>
</scene>
<!--Code View Controller-->
<scene sceneID="VW5-ny-vaB">
<objects>
<viewController storyboardIdentifier="CodeViewController" id="Lz1-1J-ywG" customClass="CodeViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Rud-1x-pKL">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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">
<rect key="frame" x="50" y="47" width="275.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="2Gj-pC-RZ2">
<rect key="frame" x="37.5" y="99" width="300" height="58"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="744-t1-YNn">
<rect key="frame" x="0.0" y="0.0" width="40" height="58"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="45"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad"/>
</textField>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="jcR-jp-s7a">
<rect key="frame" x="52" y="0.0" width="40" height="58"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="45"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad"/>
</textField>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="YKO-0M-KD8">
<rect key="frame" x="104" y="0.0" width="40" height="58"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="45"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad"/>
</textField>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="SmG-Ae-oOs">
<rect key="frame" x="156" y="0.0" width="40" height="58"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="45"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad"/>
</textField>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="vaP-rO-NZW">
<rect key="frame" x="208" y="0.0" width="40" height="58"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="45"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad"/>
</textField>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="_" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="qDh-32-HSn">
<rect key="frame" x="260" y="0.0" width="40" height="58"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="45"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad"/>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="58" id="5tl-bI-7tm"/>
<constraint firstItem="YKO-0M-KD8" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="E7r-rk-4Mb"/>
<constraint firstItem="SmG-Ae-oOs" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Hkd-L6-qkf"/>
<constraint firstItem="qDh-32-HSn" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Koj-e5-Dof"/>
<constraint firstItem="vaP-rO-NZW" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="Vzl-ZY-3yI"/>
<constraint firstItem="jcR-jp-s7a" firstAttribute="width" secondItem="744-t1-YNn" secondAttribute="width" id="bDe-cA-CGi"/>
<constraint firstAttribute="width" constant="300" id="gWy-t0-k14"/>
</constraints>
</stackView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lCU-OF-giE">
<rect key="frame" x="0.0" y="617" width="375" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AMw-Yp-yMs">
<rect key="frame" x="327" y="8" width="32" height="30"/>
<state key="normal" title="Next"/>
<connections>
<action selector="whereToGoNext:" destination="Lz1-1J-ywG" eventType="touchUpInside" id="1OA-n8-Gky"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="AMw-Yp-yMs" secondAttribute="bottom" constant="12" id="7qy-qR-6jm"/>
<constraint firstItem="AMw-Yp-yMs" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="lCU-OF-giE" secondAttribute="leading" constant="20" symbolic="YES" id="Bqz-qr-CNW"/>
<constraint firstAttribute="height" constant="50" id="Dyu-H3-S3f"/>
<constraint firstAttribute="trailing" secondItem="AMw-Yp-yMs" secondAttribute="trailing" constant="16" id="N19-bz-XCw"/>
<constraint firstItem="AMw-Yp-yMs" firstAttribute="top" secondItem="lCU-OF-giE" secondAttribute="top" constant="8" id="u6d-3F-1Y5"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="hE6-cQ-NbO" firstAttribute="top" secondItem="xwd-51-foC" secondAttribute="top" constant="27" id="8Gx-SH-Pc0"/>
<constraint firstItem="2Gj-pC-RZ2" firstAttribute="top" secondItem="hE6-cQ-NbO" secondAttribute="bottom" constant="31.5" id="DEY-u8-rFj"/>
<constraint firstItem="lCU-OF-giE" firstAttribute="leading" secondItem="xwd-51-foC" secondAttribute="leading" id="HFt-0X-LMb"/>
<constraint firstItem="lCU-OF-giE" firstAttribute="trailing" secondItem="xwd-51-foC" secondAttribute="trailing" id="Z71-jX-S5Q"/>
<constraint firstItem="2Gj-pC-RZ2" firstAttribute="centerX" secondItem="xwd-51-foC" secondAttribute="centerX" id="aSr-QZ-LuB"/>
<constraint firstItem="hE6-cQ-NbO" firstAttribute="centerX" secondItem="xwd-51-foC" secondAttribute="centerX" id="oFz-CS-SSk"/>
<constraint firstItem="lCU-OF-giE" firstAttribute="bottom" secondItem="xwd-51-foC" secondAttribute="bottom" id="vMF-KP-eIa"/>
</constraints>
<viewLayoutGuide key="safeArea" id="xwd-51-foC"/>
</view>
<connections>
<outlet property="bottomConstraint" destination="vMF-KP-eIa" id="a15-El-XZs"/>
<outlet property="f1" destination="744-t1-YNn" id="kaQ-nt-ubz"/>
<outlet property="f2" destination="jcR-jp-s7a" id="tjD-L6-nis"/>
<outlet property="f3" destination="YKO-0M-KD8" id="QHg-UM-Bta"/>
<outlet property="f4" destination="SmG-Ae-oOs" id="bwy-JB-My7"/>
<outlet property="f5" destination="vaP-rO-NZW" id="rNh-iH-648"/>
<outlet property="f6" destination="qDh-32-HSn" id="h4g-QY-abI"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="y6E-3d-hPA" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4381.6000000000004" y="1961.4692653673164"/>
</scene>
<!--Register Table View Controller-->
<scene sceneID="h6T-rh-iCS">
<objects>
<tableViewController storyboardIdentifier="RegisterTableViewController" id="gZg-8R-SiJ" customClass="RegisterTableViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<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">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Ybe-Vg-GR0" id="OZG-F0-QqJ">
<rect key="frame" x="0.0" y="0.0" width="341" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Add faculty" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="bby-bf-qyX">
<rect key="frame" x="16" y="0.0" width="324" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<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">
<rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xJW-zY-MeC" id="hnt-oe-CHh">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Add faculty" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8Xf-Sx-eEe">
<rect key="frame" x="16" y="5" width="87" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Vjg-Il-F07">
<rect key="frame" x="16" y="25.5" width="44" height="14.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="nameCell" id="VPG-zq-xMh" customClass="InititalsViewCell" customModule="GDproject" customModuleProvider="target">
<rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VPG-zq-xMh" id="jrO-rB-x0c">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="hwQ-St-DAp">
<rect key="frame" x="16" y="7" width="343" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="QXw-Sf-Hnk"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="hwQ-St-DAp" secondAttribute="bottom" constant="6.5" id="3Kb-PR-ZPu"/>
<constraint firstItem="hwQ-St-DAp" firstAttribute="top" secondItem="jrO-rB-x0c" secondAttribute="top" constant="7" id="CyQ-kQ-mce"/>
<constraint firstAttribute="trailing" secondItem="hwQ-St-DAp" secondAttribute="trailing" constant="16" id="HKq-mF-8h9"/>
<constraint firstItem="hwQ-St-DAp" firstAttribute="leading" secondItem="jrO-rB-x0c" secondAttribute="leading" constant="16" id="NoW-FW-Q6L"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="initialsTextField" destination="hwQ-St-DAp" id="VU3-m6-FnI"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="gZg-8R-SiJ" id="OVm-5H-nyP"/>
<outlet property="delegate" destination="gZg-8R-SiJ" id="khe-nG-0w4"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="0cS-ao-ZWH" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="5925.6000000000004" y="2041.529235382309"/>
</scene>
<!--Faculty Table View Controller-->
<scene sceneID="WcK-wN-L0e">
<objects>
<tableViewController storyboardIdentifier="FacultyTableViewController" id="wiz-jF-9HF" customClass="FacultyTableViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<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">
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Otu-BR-9o9" id="2Vm-f8-txH">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="mSQ-7c-C8A">
<rect key="frame" x="16" y="5" width="33.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="YuF-0p-znr">
<rect key="frame" x="16" y="25.5" width="44" height="14.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="wiz-jF-9HF" id="db0-qR-UJy"/>
<outlet property="delegate" destination="wiz-jF-9HF" id="i3e-Uc-EfR"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Kkr-Cr-ZiV" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="6804" y="2044"/>
</scene>
<!--Simplified Channels List-->
<scene sceneID="gAa-jy-vpG">
@ -354,7 +615,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="fzv-8a-15V" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3560.8000000000002" y="-597.75112443778119"/>
<point key="canvasLocation" x="3577" y="-598"/>
</scene>
<!--New Post View Controller-->
<scene sceneID="TVK-xu-UdJ">
@ -365,33 +626,35 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aRT-Du-PVE">
<rect key="frame" x="0.0" y="55" width="375" height="612"/>
<rect key="frame" x="0.0" y="62" width="375" height="605"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="368-bf-QU6">
<rect key="frame" x="0.0" y="20" width="375" height="35"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bHv-9b-9uA">
<rect key="frame" x="16" y="32" width="343" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="35" id="5ER-su-0Yf"/>
<constraint firstAttribute="height" constant="30" id="QPs-3f-AfA"/>
</constraints>
</view>
<state key="normal" title="Edit hashtags"/>
<connections>
<action selector="chooseTags:" destination="uED-wX-77j" eventType="touchUpInside" id="jvf-w2-K2f"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="aRT-Du-PVE" secondAttribute="trailing" id="2ee-e8-G7A"/>
<constraint firstItem="368-bf-QU6" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="9Rl-wh-kZf"/>
<constraint firstItem="aRT-Du-PVE" firstAttribute="top" secondItem="bHv-9b-9uA" secondAttribute="bottom" id="6As-MU-bEh"/>
<constraint firstItem="bHv-9b-9uA" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" constant="16" id="OIV-hF-TBs"/>
<constraint firstItem="bHv-9b-9uA" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" constant="12" id="REt-Jv-IfH"/>
<constraint firstItem="aRT-Du-PVE" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="UBy-Ch-zSL"/>
<constraint firstItem="aRT-Du-PVE" firstAttribute="top" secondItem="368-bf-QU6" secondAttribute="bottom" id="WaE-kh-6w3"/>
<constraint firstItem="368-bf-QU6" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" id="aI9-JQ-7dq"/>
<constraint firstItem="368-bf-QU6" firstAttribute="trailing" secondItem="wxD-Ek-mgv" secondAttribute="trailing" id="haz-0r-Cud"/>
<constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="bHv-9b-9uA" secondAttribute="trailing" constant="16" id="Ufp-mQ-Xeo"/>
<constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="aRT-Du-PVE" secondAttribute="bottom" id="x3f-eb-ACt"/>
</constraints>
<viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
</view>
<connections>
<outlet property="bottomTextViewConstraint" destination="x3f-eb-ACt" id="ktT-im-InH"/>
<outlet property="view1" destination="aRT-Du-PVE" id="m3d-kW-vqW"/>
<outlet property="viewForTags" destination="368-bf-QU6" id="M5s-RZ-Fq7"/>
<outlet property="view1" destination="aRT-Du-PVE" id="DXD-HR-NcE"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -416,54 +679,352 @@
</objects>
<point key="canvasLocation" x="3444" y="129.98500749625188"/>
</scene>
<!--Log In View Controller-->
<scene sceneID="Pkd-pB-bQs">
<!--Taggs Selection View Controller-->
<scene sceneID="74G-Lc-cqT">
<objects>
<viewController storyboardIdentifier="LogInController" id="ZCz-70-hDh" customClass="LogInViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="1q2-4g-KZs">
<viewController storyboardIdentifier="TaggsSelectionViewController" id="rQl-ri-9O8" customClass="TaggsSelectionViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="k3T-8B-NVf">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="UwC-m5-jA5">
<rect key="frame" x="16" y="100" width="343" height="83"/>
<subviews>
<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">
<rect key="frame" x="0.0" y="0.0" width="343" height="41"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="34"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Mail" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="mFP-WG-jY5">
<rect key="frame" x="0.0" y="53" width="343" height="30"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
</stackView>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="K3b-gv-JPp">
<rect key="frame" x="177.5" y="333.5" width="20" height="20"/>
</activityIndicatorView>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yeR-J3-ysT">
<rect key="frame" x="16" y="131" width="343" height="142"/>
<constraints>
<constraint firstAttribute="height" constant="142" id="1By-sC-rMT"/>
</constraints>
</containerView>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lEu-rZ-H6U">
<rect key="frame" x="16" y="306" width="343" height="184"/>
<constraints>
<constraint firstAttribute="height" constant="184" id="F0W-3R-hCj"/>
</constraints>
</containerView>
<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">
<rect key="frame" x="16" y="28" width="73" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="KZW-ld-K8d"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<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">
<rect key="frame" x="16" y="106" width="126" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="ZJb-Aw-bLx"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<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">
<rect key="frame" x="16" y="281" width="101" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="aT7-BK-i42"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<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">
<rect key="frame" x="16" y="57" width="343" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="dBr-rd-Cg8"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="UwC-m5-jA5" firstAttribute="leading" secondItem="LOR-Yw-0FU" secondAttribute="leading" constant="16" id="M6z-nU-H40"/>
<constraint firstItem="K3b-gv-JPp" firstAttribute="centerY" secondItem="LOR-Yw-0FU" secondAttribute="centerY" id="eOp-yQ-n28"/>
<constraint firstItem="K3b-gv-JPp" firstAttribute="centerX" secondItem="LOR-Yw-0FU" secondAttribute="centerX" id="gdW-VU-pE8"/>
<constraint firstItem="LOR-Yw-0FU" firstAttribute="trailing" secondItem="UwC-m5-jA5" secondAttribute="trailing" constant="16" id="jST-rr-MMX"/>
<constraint firstItem="UwC-m5-jA5" firstAttribute="top" secondItem="LOR-Yw-0FU" secondAttribute="top" constant="80" id="rvy-Ii-bwS"/>
<constraint firstItem="hvS-Ix-A23" firstAttribute="top" secondItem="BgX-NT-7NG" secondAttribute="bottom" constant="19" id="17U-ae-Gxa"/>
<constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="yeR-J3-ysT" secondAttribute="trailing" constant="16" id="9gG-QD-LG4"/>
<constraint firstItem="lxp-KC-Iua" firstAttribute="top" secondItem="yeR-J3-ysT" secondAttribute="bottom" constant="8" id="C3R-dM-Fzj"/>
<constraint firstItem="uXC-Rm-Hek" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="E6w-kw-7Uo"/>
<constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="hvS-Ix-A23" secondAttribute="trailing" constant="233" id="GLM-Fj-UeZ"/>
<constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lxp-KC-Iua" secondAttribute="trailing" constant="258" id="Pbc-Ul-Bqf"/>
<constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="uXC-Rm-Hek" secondAttribute="trailing" constant="286" id="Uc1-pS-uKg"/>
<constraint firstItem="lEu-rZ-H6U" firstAttribute="top" secondItem="lxp-KC-Iua" secondAttribute="bottom" constant="4" id="aew-vr-F7L"/>
<constraint firstItem="uXC-Rm-Hek" firstAttribute="top" secondItem="Oc2-oW-bST" secondAttribute="top" constant="8" id="dGW-ps-wNH"/>
<constraint firstItem="lxp-KC-Iua" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="gmr-z4-RMQ"/>
<constraint firstItem="BgX-NT-7NG" firstAttribute="top" secondItem="uXC-Rm-Hek" secondAttribute="bottom" constant="8" id="jqp-Lv-waU"/>
<constraint firstItem="yeR-J3-ysT" firstAttribute="top" secondItem="hvS-Ix-A23" secondAttribute="bottom" constant="4" id="nZ3-oH-0AF"/>
<constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="BgX-NT-7NG" secondAttribute="trailing" constant="16" id="pPk-Ih-GDO"/>
<constraint firstItem="yeR-J3-ysT" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qBn-xg-Ioc"/>
<constraint firstItem="lEu-rZ-H6U" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qCJ-rc-qBq"/>
<constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lEu-rZ-H6U" secondAttribute="trailing" constant="16" id="vaR-Zr-5nI"/>
<constraint firstItem="hvS-Ix-A23" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="vcb-xj-bM8"/>
<constraint firstItem="BgX-NT-7NG" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="xOL-J4-JIV"/>
</constraints>
<viewLayoutGuide key="safeArea" id="LOR-Yw-0FU"/>
<viewLayoutGuide key="safeArea" id="Oc2-oW-bST"/>
</view>
<connections>
<outlet property="indicatorView" destination="K3b-gv-JPp" id="mSR-QU-VZQ"/>
<outlet property="mailTextField" destination="mFP-WG-jY5" id="7SN-qe-DDm"/>
<outlet property="addTagsTextField" destination="BgX-NT-7NG" id="3vt-U9-NYI"/>
<outlet property="searchContainerView" destination="yeR-J3-ysT" id="SzT-fM-A6H"/>
<outlet property="testContainer" destination="lEu-rZ-H6U" id="DTe-9O-VAi"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6e8-oo-bbc" userLabel="First Responder" sceneMemberID="firstResponder"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="eoH-1e-A6A" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-466" y="-821"/>
<point key="canvasLocation" x="4293.6000000000004" y="132.68365817091455"/>
</scene>
<!--Messages View Controller-->
<scene sceneID="WSW-fr-Vf8">
<objects>
<tableViewController storyboardIdentifier="MessagesViewController" id="KLf-CK-diQ" customClass="MessagesViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<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">
<rect key="frame" x="0.0" y="28" width="375" height="78"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="67C-fT-WEV" id="O3b-Xv-UNk">
<rect key="frame" x="0.0" y="0.0" width="375" height="77.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<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">
<rect key="frame" x="229" y="11" width="130" height="15"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="130" id="f99-ZF-f8h"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<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">
<rect key="frame" x="16" y="11" width="46" height="22"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<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">
<rect key="frame" x="16" y="49" width="343" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="nTy-rK-XTr" firstAttribute="top" secondItem="xAY-IF-RpX" secondAttribute="bottom" constant="23" id="09Y-aK-nD9"/>
<constraint firstItem="FG3-gU-0r1" firstAttribute="top" secondItem="O3b-Xv-UNk" secondAttribute="topMargin" id="4Hp-d5-9An"/>
<constraint firstItem="xAY-IF-RpX" firstAttribute="top" secondItem="O3b-Xv-UNk" secondAttribute="topMargin" id="G4f-oJ-7ud"/>
<constraint firstItem="nTy-rK-XTr" firstAttribute="trailing" secondItem="O3b-Xv-UNk" secondAttribute="trailingMargin" id="MaE-VM-KhL"/>
<constraint firstItem="nTy-rK-XTr" firstAttribute="leading" secondItem="O3b-Xv-UNk" secondAttribute="leadingMargin" id="OIX-rY-Leo"/>
<constraint firstItem="nTy-rK-XTr" firstAttribute="top" secondItem="FG3-gU-0r1" secondAttribute="bottom" constant="16" id="Qdj-s3-t60"/>
<constraint firstItem="nTy-rK-XTr" firstAttribute="bottom" secondItem="O3b-Xv-UNk" secondAttribute="bottomMargin" id="Rv3-Mz-Aed"/>
<constraint firstItem="FG3-gU-0r1" firstAttribute="leading" secondItem="O3b-Xv-UNk" secondAttribute="leadingMargin" id="iN1-KG-dYn"/>
<constraint firstItem="xAY-IF-RpX" firstAttribute="trailing" secondItem="O3b-Xv-UNk" secondAttribute="trailingMargin" id="opV-4x-VCk"/>
<constraint firstItem="xAY-IF-RpX" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FG3-gU-0r1" secondAttribute="trailing" constant="4" id="x9r-sM-t4x"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="dateLabel" destination="xAY-IF-RpX" id="fcz-re-BXk"/>
<outlet property="dialogName" destination="FG3-gU-0r1" id="gd7-ND-wCi"/>
<outlet property="lastMessagePreview" destination="nTy-rK-XTr" id="Cmo-IJ-2r0"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="KLf-CK-diQ" id="LjF-Uw-Xhq"/>
<outlet property="delegate" destination="KLf-CK-diQ" id="yJZ-wH-O3v"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="fu3-z4-EY7" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2681" y="918"/>
</scene>
<!--People To Write View Controller-->
<scene sceneID="6Td-bq-Ebf">
<objects>
<tableViewController storyboardIdentifier="PeopleToWriteViewController" id="rUc-Tv-hWE" customClass="PeopleToWriteViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="peopleToWriteCell" textLabel="e4H-yo-W57" style="IBUITableViewCellStyleDefault" id="5ue-Sf-Blf">
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5ue-Sf-Blf" id="8Dr-YE-x7M">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="e4H-yo-W57">
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="rUc-Tv-hWE" id="cuc-oZ-Sna"/>
<outlet property="delegate" destination="rUc-Tv-hWE" id="hw6-6X-Rlx"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Zp5-b5-nn2" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3614" y="938"/>
</scene>
<!--Chat Info View Controller-->
<scene sceneID="1br-Xg-fR9">
<objects>
<tableViewController storyboardIdentifier="ChatInfoViewController" id="Rfd-Hp-Qqv" customClass="ChatInfoViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" textLabel="EdJ-of-2FG" style="IBUITableViewCellStyleDefault" id="hl5-Uc-R53">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hl5-Uc-R53" id="Oy5-4e-dPI">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="EdJ-of-2FG">
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<sections/>
<connections>
<outlet property="dataSource" destination="Rfd-Hp-Qqv" id="ThC-G8-che"/>
<outlet property="delegate" destination="Rfd-Hp-Qqv" id="1WG-zg-Ahf"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="KPW-41-EQd" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="5057" y="938"/>
</scene>
<!--Tags Suggestion Controller-->
<scene sceneID="gfS-IA-vBj">
<objects>
<tableViewController storyboardIdentifier="TagsSuggestionController" id="shX-JH-apo" customClass="TagsSuggestionController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="cell" textLabel="Lbu-Z7-fTN" style="IBUITableViewCellStyleDefault" id="pnl-jg-9DL">
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pnl-jg-9DL" id="Vsm-Ic-k7e">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Lbu-Z7-fTN">
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="shX-JH-apo" id="a9b-xm-VIg"/>
<outlet property="delegate" destination="shX-JH-apo" id="Cg4-aC-E7h"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="RsJ-xx-GJW" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="5925" y="1339"/>
</scene>
<!--Channel View Controller-->
<scene sceneID="myW-UY-uGB">
<objects>
<tableViewController storyboardIdentifier="ChannelViewController" id="M45-Em-JMM" customClass="ChannelViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="titleCell" id="x0n-Is-bsF" customClass="TitleCell" customModule="GDproject" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="x0n-Is-bsF" id="5aI-NN-BRQ">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name the channel" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="jTk-cs-cpn">
<rect key="frame" x="16" y="7" width="343" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="ZDL-Wx-W4e"/>
</constraints>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="jTk-cs-cpn" secondAttribute="trailing" constant="16" id="KLT-Mg-Igg"/>
<constraint firstAttribute="bottom" secondItem="jTk-cs-cpn" secondAttribute="bottom" constant="6.5" id="Yuh-81-wLm"/>
<constraint firstItem="jTk-cs-cpn" firstAttribute="leading" secondItem="5aI-NN-BRQ" secondAttribute="leading" constant="16" id="tx2-BD-LW1"/>
<constraint firstItem="jTk-cs-cpn" firstAttribute="top" secondItem="5aI-NN-BRQ" secondAttribute="top" constant="7" id="ufD-Sr-H0c"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="titleLabel" destination="jTk-cs-cpn" id="ysU-SK-thv"/>
</connections>
</tableViewCell>
</prototypes>
<sections/>
<connections>
<outlet property="dataSource" destination="M45-Em-JMM" id="zIt-LL-u3B"/>
<outlet property="delegate" destination="M45-Em-JMM" id="8oD-9d-gx0"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="W3K-lW-jpq" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="5844" y="448"/>
</scene>
<!--Add To ChannelVC-->
<scene sceneID="Qir-mq-wma">
<objects>
<tableViewController storyboardIdentifier="AddToChannelVC" id="sZD-zJ-IzQ" customClass="AddToChannelVC" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="xMi-Gz-AGg">
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xMi-Gz-AGg" id="Lj0-2E-Ai9">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="sZD-zJ-IzQ" id="RJA-hG-8Bd"/>
<outlet property="delegate" destination="sZD-zJ-IzQ" id="zlr-yK-CDk"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="kT3-kK-tSX" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="6548" y="448"/>
</scene>
<!--Posts-->
<scene sceneID="RSd-UJ-34B">
@ -476,33 +1037,10 @@
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="Nqc-TI-ueQ" kind="relationship" relationship="rootViewController" id="2BZ-i4-uIE"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="POV-5T-jeQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1088.8" y="132.68365817091455"/>
</scene>
<!--News Controller-->
<scene sceneID="eR7-97-LRL">
<objects>
<tableViewController storyboardIdentifier="NewsController" id="Nqc-TI-ueQ" customClass="NewsController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<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">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="sectionIndexBackgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<outlet property="dataSource" destination="Nqc-TI-ueQ" id="bu5-tQ-7lb"/>
<outlet property="delegate" destination="Nqc-TI-ueQ" id="kTM-Be-8qb"/>
</connections>
</tableView>
<navigationItem key="navigationItem" largeTitleDisplayMode="always" id="b8E-6f-hLM"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="c9d-Kh-itI" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1880" y="136"/>
<point key="canvasLocation" x="1089" y="-306"/>
</scene>
<!--Profile-->
<scene sceneID="dJj-Hp-Wa9">
@ -515,31 +1053,15 @@
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="R4D-Ao-uvG" kind="relationship" relationship="rootViewController" id="aF6-zK-hCB"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Fvm-qf-2Ve" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1089" y="958"/>
<point key="canvasLocation" x="1015" y="1216"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="r0M-xH-UwU">
<objects>
<navigationController storyboardIdentifier="root" id="609-2j-gc9" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Ah8-NU-AsD">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Raj-78-jlT" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-2242" y="68"/>
</scene>
<!--Tab Bar Controller-->
<!--Tabbar Controller-->
<scene sceneID="HCR-WO-p7g">
<objects>
<tabBarController storyboardIdentifier="TabBar" automaticallyAdjustsScrollViewInsets="NO" id="IeP-4W-8LT" sceneMemberID="viewController">
<tabBarController storyboardIdentifier="TabbarController" automaticallyAdjustsScrollViewInsets="NO" id="IeP-4W-8LT" customClass="TabbarController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<toolbarItems/>
<tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="3pl-mU-U30">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
@ -548,6 +1070,7 @@
</tabBar>
<connections>
<segue destination="NuV-ZG-ld2" kind="relationship" relationship="viewControllers" id="XuX-8s-fZU"/>
<segue destination="gt4-mD-66Q" kind="relationship" relationship="viewControllers" id="QM3-FF-LMu"/>
<segue destination="tae-5q-wvT" kind="relationship" relationship="viewControllers" id="wCJ-4N-lfC"/>
</connections>
</tabBarController>
@ -555,9 +1078,40 @@
</objects>
<point key="canvasLocation" x="-466" y="641"/>
</scene>
<!--News Controller-->
<scene sceneID="kf1-SJ-kcp">
<objects>
<viewController storyboardIdentifier="NewsController" id="R7p-5c-Vzl" customClass="NewsController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Kx5-cu-FC2">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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">
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="5IP-vK-phq" firstAttribute="top" secondItem="qGo-Sq-Oz2" secondAttribute="top" id="HvO-w8-yYd"/>
<constraint firstItem="5IP-vK-phq" firstAttribute="leading" secondItem="qGo-Sq-Oz2" secondAttribute="leading" id="NTk-fa-llk"/>
<constraint firstItem="qGo-Sq-Oz2" firstAttribute="bottom" secondItem="5IP-vK-phq" secondAttribute="bottom" id="mAj-tJ-R30"/>
<constraint firstItem="qGo-Sq-Oz2" firstAttribute="trailing" secondItem="5IP-vK-phq" secondAttribute="trailing" id="pcE-yb-fxC"/>
</constraints>
<viewLayoutGuide key="safeArea" id="qGo-Sq-Oz2"/>
</view>
<connections>
<outlet property="tableView" destination="5IP-vK-phq" id="EQe-eC-W7P"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6Lk-UL-mQL" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="5426" y="-235"/>
</scene>
</scenes>
<resources>
<image name="1" width="30" height="30"/>
<image name="5" width="30" height="30"/>
<image name="chat" width="30" height="30"/>
</resources>
</document>

View File

@ -6,6 +6,7 @@
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
/// constant for cell in posts NewsController.swift
let postCellId = "PostCell"
@ -42,7 +43,29 @@ let newsController = "NewsController"
/// constant for switching to view controller for log in app
let logInController = "LogInController"
/// constant for getting to messages
let messagesViewControllerId = "MessagesViewController"
/// constant for displaying list of people to send message to
let peopleToWriteVC = "PeopleToWriteViewController"
let dialogVC = "DialogViewController"
let profileViewController = "ProfileViewController"
let simplifiedChannelsList = "SimplifiedChannelsList"
let channelViewControllerId = "ChannelViewController"
let addToChannelVCId = "AddToChannelVC"
let taggsSelectionViewController = "TaggsSelectionViewController"
let dialogViewController = "DialogViewController"
let tagsSuggestionController = "TagsSuggestionController"
let chatInfoViewController = "ChatInfoViewController"
let blueSystemColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)

View File

@ -0,0 +1,132 @@
//
// AddToChannelVC.swift
// GDproject
//
// Created by cstore on 02/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
enum DataSourse{
case people, tags
}
class AddToChannelVC: UITableViewController {
var channel: Model.Channels?
weak var update: UpdatableChannel?
// data sources for people and hashtags
var dataSourcePeople: [Model.Users] = Model.Channels.fullPeople
var reloadtable: Bool = false {
didSet{
tableView.reloadData()
}
}
var filteredDataSource = [Model.Users]()
func filterContentForSearchText(_ searchText: String, scope: String = "All")
{
filteredDataSource = dataSourcePeople.filter { $0.fullName().lowercased().contains(searchText.lowercased()) }
tableView.reloadData()
}
let searchC = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "People"
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.navigationItem.searchController = searchC
navigationItem.largeTitleDisplayMode = .never
self.navigationItem.hidesSearchBarWhenScrolling = false
definesPresentationContext = true
searchC.searchResultsUpdater = self
searchC.obscuresBackgroundDuringPresentation = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
update?.updateChannel(with: channel!)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
var isFiltering: Bool {
return searchC.isActive && !searchBarIsEmpty()
}
func searchBarIsEmpty() -> Bool {
return searchC.searchBar.text?.isEmpty ?? true
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering {
return filteredDataSource.count
} else {
return dataSourcePeople.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if isFiltering{
cell.textLabel?.text = filteredDataSource[indexPath.row].fullName()
if channel!.people.contains(filteredDataSource[indexPath.row].id) {
cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
} else {
cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
}
} else {
cell.textLabel?.text = dataSourcePeople[indexPath.row].fullName()
if channel!.people.contains(dataSourcePeople[indexPath.row].id) {
cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
} else {
cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
}
}
cell.selectionStyle = .none
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
if isFiltering{
if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
let filtered = channel!.people.filter{ $0 != filteredDataSource[indexPath.row].id }
channel?.people = filtered
cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
} else {
channel?.people.append(filteredDataSource[indexPath.row].id)
cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
}
} else {
if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
let filtered = channel!.people.filter{ $0 != dataSourcePeople[indexPath.row].id }
channel?.people = filtered
cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
} else {
channel?.people.append(dataSourcePeople[indexPath.row].id)
cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
}
}
}
}
}
extension AddToChannelVC : UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}
}

View File

@ -25,7 +25,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
var channel: Model.Channels?
var myProtocol: DataDelegate?
var fullTags: [String] = Array(Model.Channels.fullTags)
var fullTags: [String] = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
var dataSourcePeople: [Model.Users] = []
@ -33,6 +33,9 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
var activeDataSource: ActiveTable = .people
// func to show preview of the current channel
var onShowingPreview: ((Model.Channels)->())?
@IBOutlet weak var viewww: UIView!
@IBOutlet weak var textField: UITextField!
@ -61,16 +64,33 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
// TODO: update channel
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let _ = channel?.id { print("update")
Model.updateChannel(with: channel!)
} else { print("create")
Model.createChannel(with: channel!)
defer {
super.viewWillDisappear(animated)
}
guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else {
if let _ = channel?.id { print("update")
Model.updateChannel(with: channel!)
} else { print("create")
//Model.createChannel(with: channel!)
}
return
}
// nou
}
@objc func showPreview(){
if let channel = channel {
onShowingPreview?(channel)
}
}
func setUpController(){
// setting up the preview button for the editing or created channel
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Preview", style: .done, target: self, action: #selector(showPreview))
tableView.delegate = self
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: itemCellId)
@ -232,9 +252,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
}
tableView.reloadData()
case 1:
dataSourceTags = fullTags.filter({ (s) -> Bool in
s.lowercased().contains(text.lowercased())
})
dataSourceTags = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: text)
tableView.reloadData()
default:
break

View File

@ -13,20 +13,24 @@ struct ChannelData{
var subtitle = String()
}
protocol ChannelListData: class {
func reloadData (with channels: [Model.Channels])
}
// TODO: make search controller availiable
class ChannelListController: UITableViewController, DataDelegate {
class ChannelListController: UITableViewController {
// MARK: - Output -
var onChannelSelected: ((Model.Channels) -> Void)?
var onEditingModeBegins: ((Model.Channels, IndexPath)->Void)?
// MARK: - filter search controller
var filteredDataSource = [Model.Channels]()
var myProtocol: DataDelegate?
var displayingChannel: Model.Channels?
var toReload: Bool = false {
didSet{
didSet {
tableView.reloadData()
}
}
@ -80,7 +84,7 @@ class ChannelListController: UITableViewController, DataDelegate {
askForUpdates()
}
private func askForUpdates(){
func askForUpdates(){
Model.channelsList { [weak self] (channels) in
self?.dataSource = [ChannelListController.generalChannel] + channels
self?.toReload = true
@ -89,17 +93,14 @@ class ChannelListController: UITableViewController, DataDelegate {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
askForUpdates()
//askForUpdates()
tabBarController?.tabBar.isHidden = false
}
@objc func addChannel()
{
// editing mode is on automatically
let vc = storyboard?.instantiateViewController(withIdentifier: channelControllerId) as! ChannelController
vc.index = 1
vc.myProtocol = self
vc.channel = Model.Channels(people: [], name: "Untitled", tags: [])
navigationController?.pushViewController(vc, animated: true)
onEditingModeBegins?(Model.Channels(people: [], name: "Untitled", id: 0, tags: []),IndexPath(row: 1, section: 0))
}
static let generalChannel = Model.Channels(people: [], name: "General", id: -1, tags: [])
@ -143,27 +144,18 @@ class ChannelListController: UITableViewController, DataDelegate {
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
{
let editButton = UITableViewRowAction(style: .normal, title: "Edit") { [weak self] (action, indexPath) in
let vc = self?.storyboard?.instantiateViewController(withIdentifier: channelControllerId) as! ChannelController
vc.index = indexPath.row
vc.myProtocol = self!
vc.channel = self?.dataSource[indexPath.row]
self?.navigationController?.pushViewController(vc, animated: true)
let editButton = UITableViewRowAction(style: .normal, title: "Edit") { [unowned self] (rowAction, indexPath) in
self.onEditingModeBegins?(self.dataSource[indexPath.row], indexPath)
}
editButton.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
editButton.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
let deleteButton = UITableViewRowAction(style: .normal, title: "Delete") { [weak self] (action, indexPath) in
Model.channelsDelete(by: self!.dataSource[indexPath.row].id!, completion: {
print("хз что тут делать при успехе")
})
if (self!.dataSource[indexPath.row].id == self!.displayingChannel?.id ?? -1)
{
self?.myProtocol?.passData(for: 0, channel: self!.dataSource[0])
}
self?.tableView.beginUpdates()
self?.dataSource.remove(at: indexPath.row)
self?.tableView.deleteRows(at: [indexPath], with: .none)
@ -175,17 +167,12 @@ class ChannelListController: UITableViewController, DataDelegate {
return [editButton, deleteButton]
}
// TODO: remove popping
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if isFiltering {
//onChannelSelected?(filteredDataSource[indexPath.row])
myProtocol?.passData(for: 0, channel: filteredDataSource[indexPath.row])
navigationController?.popViewController(animated: true)
onChannelSelected?(filteredDataSource[indexPath.row])
} else {
myProtocol?.passData(for: 0, channel: dataSource[indexPath.row])
navigationController?.popViewController(animated: true)
//onChannelSelected?(ChannelListController.dataSource[indexPath.row])
onChannelSelected?(dataSource[indexPath.row])
}
}
}

View File

@ -0,0 +1,208 @@
//
// ChannelViewController.swift
// MessageApp
//
// Created by cstore on 02/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
protocol UpdatableName: class{
func updateName(with name: String)
}
protocol UpdatableChannel: class{
func updateChannel(with channel: Model.Channels)
}
class ChannelViewController: UITableViewController, UpdatableName, UpdatableChannel, TagsReceiver
{
var onChoosingHashTags: (([String]?)->())?
var onChoosingPeople: ((Model.Channels?)->())?
func receiveTags(tags: [String]) {
self.channel?.tags = tags
}
func updateName(with name: String){
channel?.name = name
}
func updateChannel(with channel: Model.Channels) {
self.channel = channel
}
var channel: Model.Channels?
// func to show preview of the current channel
var onShowingPreview: ((Model.Channels)->())?
override func viewDidLoad()
{
super.viewDidLoad()
tableView.keyboardDismissMode = .onDrag
navigationItem.rightBarButtonItems = [ UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(showPreview)), self.editButtonItem]
navigationItem.largeTitleDisplayMode = .never
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "searchCell")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
override func viewWillDisappear(_ animated: Bool) {
defer {
super.viewWillDisappear(animated)
}
guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else
{
if let id = channel?.id, id != 0
{
Model.updateChannel(with: channel!)
} else {
Model.createChannel(with: channel!) {
[weak self] in
self?.showAlertOn(result: $0)
return
}
}
return
}
// nou
}
@objc func showPreview()
{
if let channel = channel {
onShowingPreview?(channel)
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 1:
return (channel?.people.count ?? 0) + 1
case 2:
return (channel?.tags.count ?? 0) + 1
default:
return 1
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 1:
return "People"
case 2:
return "Tags"
default:
return "Title"
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section{
case 1 , 2:
return whichCell(tableView, cellForRowAt: indexPath)
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "titleCell") as! TitleCell
cell.fill(title: channel?.name)
cell.update = self
return cell
}
}
private func whichCell(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let row = indexPath.row
let section = indexPath.section
if row == 0
{
let cell = tableView.dequeueReusableCell(withIdentifier: "searchCell")!
cell.textLabel?.text = "Add more"
cell.accessoryType = .disclosureIndicator
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if section == 1 {
cell.textLabel?.text = "👤 \(Model.Channels.fullPeopleDict[channel?.people[row-1] ?? 0]!.fullName())"
} else {
cell.textLabel?.text = "# \(channel!.tags[row-1])"
}
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == UITableViewCell.EditingStyle.delete
{
if indexPath.section == 1 {
channel?.people.remove(at: indexPath.row-1)
} else {
channel?.tags.remove(at: indexPath.row-1)
}
}
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
if indexPath.row == 0 {
return false
}
return true
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if indexPath.row == 0 && indexPath.section == 1
{
onChoosingPeople?(channel)
}
if indexPath.row == 0 && indexPath.section == 2 {
onChoosingHashTags?(channel?.tags)
}
}
}
class TitleCell: UITableViewCell, UITextFieldDelegate {
@IBOutlet weak var titleLabel: UITextField!
weak var update: UpdatableName?
override func awakeFromNib() {
super.awakeFromNib()
}
func fill(title: String?){
titleLabel.text = title
titleLabel.addTarget(self, action: #selector(changedText(_:)), for: .editingChanged)
}
@objc func changedText(_ textField: UITextField){
update?.updateName(with: textField.text!)
}
}

View File

@ -1,55 +0,0 @@
//
// ChannelsCoordinator.swift
// GDproject
//
// Created by cstore on 23/02/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
final class ChannelsCoordinator{
// MARK: - Properties
private var channel: Model.Channels { didSet { updateInterfaces() } }
private weak var navigationController: UINavigationController?
// MARK:- Init
init(currentChannel: Model.Channels, navigationController: UINavigationController) {
self.channel = currentChannel
self.navigationController = navigationController
}
func start(){
showCurrentChannel()
}
// MARK: - Private implementation
private func showListOfChannels(){
let controller = UIStoryboard.makeChannelsListController()
controller.onChannelSelected = { [weak self] channel
in
self?.channel = channel
_ = self?.navigationController?.popViewController(animated: true)
}
navigationController?.pushViewController(controller, animated: true)
}
private func showCurrentChannel(){
let controller = UIStoryboard.makeNewsController()
controller.channel = channel
controller.onSelectChannel = { [weak self] in
self?.showListOfChannels()
}
navigationController?.setViewControllers([controller], animated: false)
//navigationController?.pushViewController(controller, animated: false)
}
// MARK:- update only viewControllers which are depandable on chosen channel
private func updateInterfaces() {
navigationController?.viewControllers.forEach {
($0 as? UpdateableWithChannel)?.channel = channel
}
}
}

View File

@ -25,27 +25,10 @@ class FullPostController: UITableViewController {
func setUpNavigationBar(){
navigationItem.largeTitleDisplayMode = .never
navigationItem.title = "\(post?.authorId ?? 0)"
navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(self.options))]
navigationItem.title = "Post"
}
@objc func options(){
// drafts
// saved
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let editAction = UIAlertAction(title: "Send via message", style: .default)
let shareAction = UIAlertAction(title: "Send via project", style: .default)
let settingsAction = UIAlertAction(title: "Copy link", style: .default)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
optionMenu.addAction(editAction)
optionMenu.addAction(shareAction)
optionMenu.addAction(settingsAction)
optionMenu.addAction(cancelAction)
self.present(optionMenu, animated: true, completion: nil)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
@ -102,6 +85,7 @@ class FullPostController: UITableViewController {
cell.onUserDisplay = { [weak self] (id) in
let vc = self?.storyboard!.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
vc.idProfile = id
self?.navigationController?.pushViewController(vc, animated: true)
}
default:

View File

@ -10,23 +10,38 @@ import UIKit
import Cartography
import Marklight
import TinyConstraints
import WSTagsField
import TaggerKit
// import WSTagsField
class NewPostViewController: UIViewController, UITextViewDelegate {
class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
{
func receiveTags(tags: [String]) {
currentTags = tags
}
@IBOutlet weak var view1: UIView!
@IBOutlet weak var viewForTags: UIView!
var currentTags: [String] = []
fileprivate let tagsField = WSTagsField()
// We want the whole experience, let's create two TKCollectionViews
let productTags = TKCollectionView()
@IBAction func chooseTags(_ sender: UIButton) {
let vc = storyboard?.instantiateViewController(withIdentifier: taggsSelectionViewController) as! TaggsSelectionViewController
NewPostViewController.draft = textView.text
vc.receiver = self
vc.currentTags = currentTags
navigationController?.pushViewController(vc, animated: true)
}
// fileprivate let tagsField = WSTagsField()
// Keep strong instance of the `NSTextStorage` subclass
let textStorage = MarklightTextStorage()
weak var parentVC: NewsController?
var myProtocol: NewPostDelegate?
static var draft: String = ""
static var hashTagsDraft: [String] = []
static var hashTagsDraft: [String] = [ ]
var textView: UITextView!
@ -57,11 +72,11 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
setUpMD()
setUpTextView()
setUpAccessoryView()
setUpTagsView()
// setUpAccessoryView()
//setUpTagsView()
}
func setUpTagsView(){
/* func setUpTagsView(){
tagsField.frame = viewForTags.bounds
viewForTags.addSubview(tagsField)
@ -89,15 +104,16 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
tagsField.acceptTagOption = .space
textFieldEvents()
}
}*/
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.prefersLargeTitles = false
//navigationController?.navigationBar.prefersLargeTitles = false
navigationItem.largeTitleDisplayMode = .never
navigationItem.title = "New post"
textView.text = NewPostViewController.draft
tagsField.addTags(NewPostViewController.hashTagsDraft)
// tagsField.addTags(NewPostViewController.hashTagsDraft)
}
@ -125,7 +141,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
func setUpTextView(){
view.addConstraint(bottomTextViewConstraint)
view1.addSubview(textView)
textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(40+8) + .right(8))
textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(8) + .right(8))
if #available(iOS 11.0, *) {
textView.smartDashesType = .no
@ -194,7 +210,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
}
func setUpMD(){
textStorage.marklightTextProcessor.codeColor = UIColor.orange
textStorage.marklightTextProcessor.codeColor = UIColor.gray
textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
textStorage.marklightTextProcessor.codeFontName = "Courier"
@ -216,10 +232,27 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
var indexOfPost = 0
// MARK:- new post
@objc func newPost(){
Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: tagsField.tags.map { $0.text })
self.navigationItem.title = "Sending..."
Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: currentTags) {
[weak self] in
switch $0 {
case .success1, .success:
NewPostViewController.draft = ""
NewPostViewController.hashTagsDraft = []
self?.moveBackToParentVC?()
default:
self?.showAlertOn(result: $0)
self?.navigationItem.title = "New post"
}
}
// NewPostViewController.draft = ""
// NewPostViewController.hashTagsDraft = []
// adding row to uiTableView after adding new post
// myProtocol?.addPost(post: p)
moveBackToParentVC()
// moveBackToParentVC?()
// somewhere here i will be sending server notifications about new post arrival
}
@ -231,8 +264,8 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
[weak self]
_ in
NewPostViewController.draft = self?.textView.text ?? ""
NewPostViewController.hashTagsDraft = self?.tagsField.tags.map { $0.text } ?? []
self?.moveBackToParentVC()
NewPostViewController.hashTagsDraft = self?.currentTags ?? []
self?.moveBackToParentVC?()
}
let deleteAction = UIAlertAction(title: "Delete draft", style: .destructive)
@ -241,7 +274,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
in
NewPostViewController.draft = ""
NewPostViewController.hashTagsDraft = []
self?.moveBackToParentVC()
self?.moveBackToParentVC?()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
@ -258,16 +291,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
actionSaveDraft()
}
func moveBackToParentVC(){
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.reveal
transition.subtype = CATransitionSubtype.fromBottom
navigationController?.view.layer.add(transition, forKey: nil)
navigationController?.popViewController(animated: false)
textView!.resignFirstResponder()
}
var moveBackToParentVC: (()->())?
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
@ -281,7 +305,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
textView.scrollRectToVisible(rect, animated: animated)
}
fileprivate func textFieldEvents() {
/*fileprivate func textFieldEvents() {
tagsField.onDidAddTag = { _, _ in
print("onDidAddTag")
}
@ -305,16 +329,16 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
tagsField.onDidUnselectTagView = { _, tagView in
print("Unselect \(tagView)")
}
}
}*/
}
extension NewPostViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == tagsField {
/*if textField == tagsField {
textView.becomeFirstResponder()
}
}*/
return true
}

View File

@ -12,72 +12,49 @@ import Cartography
protocol UpdateableWithChannel: class {
var channel: Model.Channels? { get set }
func updateChannel(on channel: Model.Channels)
}
protocol NewPostDelegate {
func addPost(post: Post)
}
protocol UpdateableWithUser: class {
var user: Model.Users? { get set }
}
// MARK:- Controller with posts and channels availiable.
// Search is availiable within every table (posts and channels). Has button-functionality for boths post and chnnels
class NewsController: UITableViewController, UISearchControllerDelegate, NewPostDelegate, UpdateableWithChannel, DataDelegate
class NewsController: UIViewController, UISearchControllerDelegate, UpdateableWithChannel, UISearchResultsUpdating
{
func passData(for row: Int, channel: Model.Channels) {
if channel.id == -1{
self.channel = nil
} else {
self.channel = channel
}
func updateChannel(on channel: Model.Channels) {
self.channel = channel
news.currChannel = channel
decideWhatChannelDisplay()
}
var dictionary: [Int: Model.Users]? {
didSet {
var newPosts: [Model.Posts] = []
posts!.forEach({ (post) in
newPosts.append(Model.Posts(body: post.body, authorId: post.authorId, id: post.id, user: dictionary![post.authorId]!, date: post.updated, tags: post.tags))
post.tags.forEach { Model.Channels.fullTags.insert($0) }
})
news.dataSourse = newPosts
tableView.reloadData()
}
}
var changedChannelName: ((String)->())?
var posts: [Model.Posts]? {
didSet{
}
}
@IBOutlet weak var tableView: UITableView!
var channel: Model.Channels? {
didSet {
navigationItem.title = channel?.name ?? ""
}
}
var channel: Model.Channels?
var anonymousChannel: (users: [Int: Model.Users], posts: [Model.Posts])?
// MARK: - Output -
var onSelectChannel: (() -> Void)?
func addPost(post: Post) {
//news.dataSourse.insert(post, at: 0)
}
var searchController = UISearchController(searchResultsController: nil)
var searchController: UISearchController?
var news = NewsVC()
var type: HeaderType? = .NEWS
var refreshContr = UIRefreshControl()
override func viewDidLoad()
{
super.viewDidLoad()
let updater = TagsSuggestionController()
updater.delegate = self
searchController = UISearchController(searchResultsController: updater)
navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Loading ..."
tableView.refreshControl = refreshContr
// Configure Refresh Control
@ -86,25 +63,26 @@ class NewsController: UITableViewController, UISearchControllerDelegate, NewPost
tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
// setUpSearchContr()
setUpSearchContr()
// navigationItem.
news.viewController = self
news.type = .NEWS
news.type = type == .NEWS ? .NEWS : type!
news.currChannel = channel
setUpNavigationItemsforPosts()
//setUpBanner()
}
func setUpSearchContr(){
searchController.delegate = self
searchController.obscuresBackgroundDuringPresentation = false
searchController?.delegate = self
searchController?.obscuresBackgroundDuringPresentation = false
navigationItem.searchController = searchController
definesPresentationContext = true
searchController.searchBar.placeholder = "Search anything"
searchController?.searchResultsUpdater = self
searchController?.searchBar.placeholder = "Search tags"
}
@objc func refreshPostsData( _ ff: UIRefreshControl){
@objc func refreshPostsData( _ ff: UIRefreshControl) {
decideWhatChannelDisplay()
}
@ -112,19 +90,9 @@ class NewsController: UITableViewController, UISearchControllerDelegate, NewPost
print("news clear")
}
let label : UILabel = {
let label = UILabel()
label.text = "No posts to display yet!"
label.font = UIFont.systemFont(ofSize: 18)
label.textColor = .black
label.isHidden = true
label.numberOfLines = 0
return label
}()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
searchController.isActive = false
searchController?.isActive = false
// TODO:- display something if no posts are availiable
decideWhatChannelDisplay()
@ -133,128 +101,59 @@ class NewsController: UITableViewController, UISearchControllerDelegate, NewPost
}
func decideWhatChannelDisplay(){
if let channel = channel, let id = channel.id {
Model.getChannel(with: id) { [weak self] in
self?.posts = $0.posts
self?.dictionary = $0.users
self?.refreshContr.endRefreshing()
switch type! {
case .NEWS, .NONE:
if let channel = channel, let id = channel.id, id != -1 {
Model.getAnonymousChannel(by: channel) { [weak self] in
self?.news.dataSourse = $0.posts
self?.news.dictionary = $0.users
self?.refreshContr.endRefreshing()
self?.changedChannelName?(channel.name)
}
} else {
Model.getLast { [weak self] in
self?.news.dataSourse = $0.posts
self?.news.dictionary = $0.users
self?.refreshContr.endRefreshing()
self?.changedChannelName?("General")
}
}
} else {
Model.getLast { [weak self] in
self?.posts = $0.posts
self?.dictionary = $0.users
self?.refreshContr.endRefreshing()
self?.navigationItem.title = "General"
}
default:
refreshContr.endRefreshing()
break
}
}
func setUpNavigationItemsforPosts(){
navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(self.writePost(_:))),UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(self.showChannels(_:)))
]
tableView.delegate = news
tableView.dataSource = news
tableView.reloadData()
}
// MARK:- attempt with coordinator
@objc func showChannels(_ barItem: UIBarButtonItem){
let vc = UIStoryboard.makeChannelsListController()
vc.myProtocol = self
vc.displayingChannel = channel
self.navigationController?.pushViewController(vc, animated: true)
}
@objc func writePost(_ barItem: UIBarButtonItem)
func updateSearchResults(for searchController: UISearchController)
{
let vc = storyboard?.instantiateViewController(withIdentifier: "NewPostViewController") as! NewPostViewController
vc.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Post", style: .plain, target: vc, action: #selector(vc.newPost))
vc.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: vc, action: #selector(vc.closeView))
vc.myProtocol = self
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.moveIn
transition.subtype = CATransitionSubtype.fromTop
navigationController?.view.layer.add(transition, forKey: nil)
navigationController?.pushViewController(vc, animated: false)
}
// for animating the banner
var topConstraint: NSLayoutConstraint?
let bannerView: UIView = {
let view = UIView()
view.backgroundColor = .blue
view.layer.cornerRadius = 25.0
view.clipsToBounds = true
return view
}()
let statusLabel: UILabel = {
let label = UILabel()
label.text = "-"
label.textColor = .white
label.textAlignment = .center
return label
}()
// MARK:- banner
private func setUpBanner()
{
view.addSubview(bannerView)
bannerView.addSubview(statusLabel)
statusLabel.edgesToSuperview()
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
bannerView.addGestureRecognizer(tap)
topConstraint = NSLayoutConstraint(item: bannerView, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .top, multiplier: 1, constant: -300)
view.addConstraint(topConstraint!)
bannerView.edgesToSuperview(excluding: [.bottom, .top, .left], insets: .right(20), usingSafeArea: true)
bannerView.height(50)
bannerView.width(50)
}
// when table is scrolling no deletion is availiable
@objc func handleTap(sender: UITapGestureRecognizer? = nil) {
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
// isBannerVisible = false
// changeConstraint(isVisible: false)
}
// animation for banner
func changeConstraint(isVisible: Bool){
topConstraint?.constant = isVisible ? 50 : -300
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}) { (completed) in
let filteredData = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: searchController.searchBar.text?.lowercased() ?? "")
// Apply the filtered results to the search results table.
if let resultsController = searchController.searchResultsController as? TagsSuggestionController {
resultsController.suggestions = filteredData
resultsController.tableView.reloadData()
}
}
var isBannerVisible: Bool = false
func willPresentSearchController(_ searchController: UISearchController) {
searchController.searchResultsController?.view.isHidden = false;
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
print(scrollView.contentOffset.y)
if scrollView.contentOffset.y >= 50 && !isBannerVisible{
isBannerVisible = true
changeConstraint(isVisible: true)
}
if isBannerVisible && scrollView.contentOffset.y == 0{
isBannerVisible = false
changeConstraint(isVisible: false)
}
func didPresentSearchController(_ searchController: UISearchController) {
searchController.searchResultsController?.view.isHidden = false;
}
func didDismissSearchController(_ searchController: UISearchController) {
searchController.searchBar.text = ""
}
}

View File

@ -19,20 +19,40 @@ struct PostCellData{
let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
markdownParser.enabledElements = .disabledAutomaticLink
markdownParser.code.textBackgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
markdownParser.code.font = UIFont(name: "Menlo", size: 16)
markdownParser.code.textBackgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
markdownParser.code.color = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
return markdownParser.parse(markdown)
}
}
class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var onChannelDidChange: ((([Int: Model.Users],[Model.Posts]))->())?
var onFullPost: ((HeaderType, Model.Posts)->())?
var dictionary: [Int: Model.Users] = [:] {
didSet {
dataSourse = dataSourse.map {
var copy = $0
copy.user = dictionary[$0.authorId]
return copy
}
(viewController as? NewsController)?.tableView.reloadData()
(viewController as? ProfileViewController)?.tableView.reloadData()
}
}
var currChannel : Model.Channels?
var dataSourse: [Model.Posts] = [] {
didSet {
cellDataSourse = []
dataSourse.forEach { (item) in
cellDataSourse.append(PostCellData(attributedData: PostCellData.create(with: item.body)))
}
cellDataSourse = dataSourse.map { PostCellData(attributedData: PostCellData.create(with: $0.body)) }
}
}
@ -48,11 +68,7 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
tableView.deselectRow(at: indexPath, animated: true)
let vc = viewController!.storyboard!.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
vc.type = type
vc.post = dataSourse[indexPath.row]
viewController!.navigationController!.pushViewController(vc, animated: true)
onFullPost?(type, dataSourse[indexPath.row])
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@ -72,9 +88,14 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
vc.idProfile = id
self?.viewController!.navigationController!.pushViewController(vc, animated: true)
}
case .NONE:
cell.onAnonymousChannelDisplay = {
[weak self] in
(self?.viewController as? UpdateableWithChannel)?.updateChannel(on: Model.Channels(people: [], name: $0, id: 0, tags: [$0]))
}
default:
cell.onUserDisplay = { (id) in
print("tapped when profile is open already \(id)")
print("tapped when profile is opened already \(id)")
}
}
@ -89,10 +110,37 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 100.0
}
}
var prevLast = -1
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
// pagination
if indexPath.row == cellDataSourse.count - 1 && prevLast != indexPath.row
{
if let ch = currChannel, let id = ch.id, id != -1 {
// check this!
Model.getAnonymousChannel(by: ch, exclusiveFrom: dataSourse.last?.id) { [weak self] in
self?.dataSourse.append(contentsOf: $0.posts)
$0.users.forEach { self?.dictionary[$0.key] = $0.value }
}
} else {
// check this!
Model.getLast(on: 10, from: dataSourse.last?.id )
{ [weak self] in
self?.dataSourse.append(contentsOf: $0.posts)
$0.users.forEach { self?.dictionary[$0.key] = $0.value }
}
}
prevLast = indexPath.row
}
}
}
enum HeaderType {
case NONE
case NEWS
case ANONYMOUS
}

View File

@ -8,13 +8,15 @@
import UIKit
import Cartography
import MarkdownKit
import TinyConstraints
class PostViewCell: UITableViewCell
{
var onUserDisplay: ((Int)->())?
var onAnonymousChannelDisplay: ((String)->())?
let nameLabel: UIButton = {
let button = UIButton()
button.setTitleColor(.black, for: .normal)
@ -40,6 +42,7 @@ class PostViewCell: UITableViewCell
let shareButton: UIButton = {
let button = UIButton(type: UIButton.ButtonType.detailDisclosure)
button.isHidden = true
return button
}()
@ -84,7 +87,7 @@ class PostViewCell: UITableViewCell
nameLabel.setTitle("\(post.user?.firstName ?? "") \(post.user?.lastName ?? "")", for: .normal)
nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
if let user = post.user{
fullNameLabel.text = "\(user.firstName) \(user.middleName) \(user.lastName)"
fullNameLabel.text = "\(user.faculty.name)"
}
else {
fullNameLabel.text = "\(post.authorId)"
@ -120,8 +123,8 @@ class PostViewCell: UITableViewCell
for hash in hashtags {
let button = UIButton()
button.setTitle("#" + hash, for: .normal)
//button.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
//button.layer.cornerRadius = 10
button.addTarget(self, action: #selector(setAnonymousChannel(on:)), for: .touchUpInside)
// button.addGestureRecognizer(longPressRecognizer)
button.titleLabel?.font = UIFont.monospacedDigitSystemFont(ofSize: 15, weight: .semibold)
button.setTitleColor(#colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1), for: .normal)
buttons.append(button)
@ -179,7 +182,13 @@ class PostViewCell: UITableViewCell
}
@objc func displayProfile(){
print("buttonTapped")
onUserDisplay?(post!.authorId)
if let id = post?.authorId {
onUserDisplay?(id)
}
}
@objc func setAnonymousChannel(on button: UIButton){
print("\(button.titleLabel?.text ?? "nothing")")
onAnonymousChannelDisplay?(String(button.titleLabel!.text!.dropFirst()))
}
}

View File

@ -0,0 +1,106 @@
//
// TaggsSelectionViewController.swift
// GDproject
//
// Created by cstore on 03/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
import TaggerKit
protocol TagsReceiver: class {
func receiveTags(tags: [String])
}
class TaggsSelectionViewController: UIViewController {
@IBOutlet weak var addTagsTextField: TKTextField!
@IBOutlet weak var searchContainerView: UIView!
@IBOutlet weak var testContainer: UIView!
// We want the whole experience, let's create two TKCollectionViews
let productTags = TKCollectionView()
let allTags = TKCollectionView()
var currentTags: [String]?
weak var receiver: TagsReceiver?
// MARK: - Lifecycle Methods
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Hashtags"
addTagsTextField.delegate = self
// Customisation example
// testCollection.customFont = UIFont.boldSystemFont(ofSize: 14) // Custom font
// testCollection.customCornerRadius = 14.0 // Corner radius of tags
// testCollection.customSpacing = 20.0 // Spacing between cells
// testCollection.customBackgroundColor = UIColor.red // Background of cells
// These are the tags already added by the user, give an aray of strings to the collection
if let tags = currentTags {
productTags.tags = tags
}
// These are intended to be all the tags the user has added in the app, which are going to be filtered
allTags.tags = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
/*
We set this collection's action to .removeTag,
becasue these are supposed to be the tags the user has already added
*/
productTags.action = .removeTag
// Set the current controller as the delegate of both collections
productTags.delegate = self
allTags.delegate = self
// "testCollection" takes the tags sent by "searchCollection"
allTags.receiver = productTags
// The tags in "searchCollection" are going to be added, so we set the action to addTag
allTags.action = .addTag
// Set the sender and receiver of the TextField
addTagsTextField.sender = allTags
addTagsTextField.receiver = productTags
add(productTags, toView: testContainer)
add(allTags, toView: searchContainerView)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let receiver = receiver{
receiver.receiveTags(tags: productTags.tags)
}
}
/*
These methods come from UIViewController now conforming to TKCollectionViewDelegate,
You use these to do whatever you want when a tag is added or removed (e.g. save to file, etc)
*/
override func tagIsBeingAdded(name: String?) {
// Example: save testCollection.tags to UserDefault
print("added \(name!)")
}
override func tagIsBeingRemoved(name: String?) {
print("removed \(name!)")
}
}
// textField deletage to close keyboard on return
extension TaggsSelectionViewController: UITextFieldDelegate
{
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
self.view.endEditing(true)
return false
}
}

View File

@ -0,0 +1,52 @@
//
// AnonimousChannelController.swift
// GDproject
//
// Created by cstore on 20/04/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
class TagsSuggestionController: UITableViewController
{
weak var delegate: UpdateableWithChannel?
var suggestions = [String]()
var channel: Model.Channels?
override func viewDidLoad()
{
super.viewDidLoad()
if let tree = Model.hashTagTree {
suggestions = CompletionTree.getCompletion(tree: tree, word: "")
print(suggestions)
}
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return suggestions.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = suggestions[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
channel = Model.Channels(people: [], name: "\(self.suggestions[indexPath.row])", id: 0, tags: [self.suggestions[indexPath.row]])
delegate?.updateChannel(on: channel!)
self.dismiss(animated: true)
}
}

View File

@ -1,14 +0,0 @@
import UIKit
class TabbarCoordinator{
var window: UIWindow!
func start(){
let tabbar = UIStoryboard.tabBarController()
window.rootViewController = tabbar
}
init(window: UIWindow) {
self.window = window
}
}

View File

@ -0,0 +1,69 @@
//
// ApplicationCoordinator.swift
// RxSwift
//
// Created by cstore on 04/03/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
fileprivate enum LaunchInstructor {
case main, auth
static func configure(
isAutorized: Bool = DataStorage.standard.isLoggedIn) -> LaunchInstructor {
if isAutorized{
return .main
} else {
return .auth
}
}
}
final class ApplicationCoordinator: BaseCoordinator{
private var window: UIWindow!
init(window: UIWindow) {
self.window = window
}
private var instructor: LaunchInstructor {
return LaunchInstructor.configure()
}
override func start() {
switch instructor {
case .auth: runAuthFlow()
case .main: runMainFlow()
}
}
private func runAuthFlow() {
let coordinator = LogInCoordinator(window: window)
coordinator.didEndFlow = { [weak self, weak coordinator] in
self?.start()
self?.removeDependency(coordinator)
}
addDependency(coordinator)
coordinator.start()
}
private func runMainFlow() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBar = storyboard.instantiateViewController(withIdentifier: "TabbarController") as! TabbarController
let coordinator = TabBarCoordinator(tabbarView: tabBar, window: window!)
coordinator.didEndFlow = { [weak self, weak coordinator] in
self?.start()
self?.removeDependency(coordinator)
}
addDependency(coordinator)
coordinator.start()
}
}

View File

@ -0,0 +1,47 @@
//
// BaseCoordinator.swift
// RxSwift
//
// Created by cstore on 02/03/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
protocol Coordinator: class {
func start()
}
class BaseCoordinator: Coordinator {
var childCoordinators: [Coordinator] = []
func start() {
}
// add only unique object
func addDependency(_ coordinator: Coordinator) {
guard !childCoordinators.contains(where: { $0 === coordinator }) else { return }
childCoordinators.append(coordinator)
}
func removeDependency(_ coordinator: Coordinator?) {
guard
childCoordinators.isEmpty == false,
let coordinator = coordinator
else { return }
// Clear child-coordinators recursively
if let coordinator = coordinator as? BaseCoordinator, !coordinator.childCoordinators.isEmpty {
coordinator.childCoordinators
.filter({ $0 !== coordinator })
.forEach({ coordinator.removeDependency($0) })
}
for (index, element) in childCoordinators.enumerated() where element === coordinator {
childCoordinators.remove(at: index)
break
}
}
}

View File

@ -0,0 +1,139 @@
//
// ChannelsCoordinator.swift
// RxSwift
//
// Created by cstore on 03/03/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
import Pulley
class ChannelsCoordinator: BaseCoordinator{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
private weak var navigationController: UINavigationController?
init(nc: UINavigationController) {
self.navigationController = nc
navigationController?.navigationItem.largeTitleDisplayMode = .always
}
override func start() {
show()
}
private func show() {
let channels = storyboard.instantiateViewController(withIdentifier: channelListControllerId) as! ChannelListController
channels.onChannelSelected = { [unowned self]
(channel) in
self.navigationController?.pushViewController(self.presentNewsController(with: channel), animated: true)
}
channels.askForUpdates()
channels.onEditingModeBegins = { [unowned self] (channel, indexPath) in
let vc = self.presentChannelController(with: channel)
self.navigationController?.pushViewController(vc, animated: true)
vc.tabBarController?.tabBar.isHidden = true
}
let nc = presentNewsController()
navigationController?.setViewControllers([channels, nc], animated: false)
}
/// Function that presents channel controller
///
/// - Parameter channel: channel that needs to be displayed
func presentChannelController(with channel: Model.Channels? = nil) -> ChannelViewController {
let mainContentVC = storyboard.instantiateViewController(withIdentifier: channelViewControllerId) as! ChannelViewController
// to show preview we need to instantiate newsController but with different functionality
mainContentVC.onShowingPreview = { [weak mainContentVC, unowned self] ch in
let vc = self.presentNewsController(with: ch, previewMode: true)
mainContentVC?.navigationController?.pushViewController(vc, animated: true)
}
// to go for choosing hashtags
mainContentVC.onChoosingHashTags = { [weak mainContentVC, unowned self] ch in
let vc = self.storyboard.instantiateViewController(withIdentifier: taggsSelectionViewController) as! TaggsSelectionViewController
vc.currentTags = ch
vc.receiver = mainContentVC
self.navigationController?.pushViewController(vc, animated: true)
}
mainContentVC.onChoosingPeople = { [weak mainContentVC, unowned self] channel in
let vc = self.storyboard.instantiateViewController(withIdentifier: addToChannelVCId) as! AddToChannelVC
vc.channel = channel
vc.update = mainContentVC
self.navigationController?.pushViewController(vc, animated: true)
}
mainContentVC.channel = channel
return mainContentVC
}
func presentNewsController(with channel: Model.Channels? = nil, previewMode: Bool = false) -> NewsController
{
let mainContentVC = storyboard.instantiateViewController(withIdentifier: newsController) as! NewsController
mainContentVC.channel = channel
if !previewMode {
mainContentVC.news.onFullPost = {
[weak self] (type,post) in
let vc = self?.storyboard.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
vc.type = type
vc.post = post
self?.navigationController!.pushViewController(vc, animated: true)
}
mainContentVC.news.onChannelDidChange = {
print("anon with \($0.0.count) users")
}
mainContentVC.navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(writePost(_:)))
]
}
mainContentVC.changedChannelName = {
[weak mainContentVC] (title) in mainContentVC?.navigationItem.title = title
}
return mainContentVC
}
@objc private func writePost(_ barItem: UIBarButtonItem)
{
let vc = storyboard.instantiateViewController(withIdentifier: "NewPostViewController") as! NewPostViewController
vc.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Post", style: .plain, target: vc, action: #selector(vc.newPost))
vc.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: vc, action: #selector(vc.closeView))
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.moveIn
transition.subtype = CATransitionSubtype.fromTop
navigationController?.view.layer.add(transition, forKey: nil)
navigationController?.pushViewController(vc, animated: false)
vc.moveBackToParentVC = {
[weak self] in
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.reveal
transition.subtype = CATransitionSubtype.fromBottom
self?.navigationController?.view.layer.add(transition, forKey: nil)
self?.navigationController?.popViewController(animated: false)
}
}
}

View File

@ -0,0 +1,70 @@
//
// LogInCoordinator.swift
// RxSwift
//
// Created by cstore on 01/03/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
class LogInCoordinator: BaseCoordinator {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var didEndFlow: (()->())?
var window: UIWindow!
var navigationController: UINavigationController?
init(window: UIWindow) {
self.window = window
self.window?.rootViewController = UINavigationController()
self.navigationController = window.rootViewController as? UINavigationController
}
override func start(){
let logInVC = LogInViewController()
logInVC.authenticate = { [weak self, weak logInVC] (email) in
DataStorage.standard.setEmail(email: email)
Model.authenticate(with: email) { [weak self]
(authStatus) in
print(authStatus.userStatus)
if (authStatus.userStatus == "invalid") {
logInVC?.presentAlertInvalidCode()
}
else if (authStatus.userStatus == "canRegister") { // register form
self?.presentRegisterVC()
} else { // validation code
self?.presentViewControllerForCodeInput()
}
}
}
navigationController?.pushViewController(logInVC, animated: false)
}
func presentViewControllerForCodeInput()
{
let vc = storyboard.instantiateViewController(withIdentifier: "CodeViewController") as! CodeViewController
self.navigationController?.pushViewController(vc, animated: true)
vc.onSuccessLogIn = {
[weak self] in self?.didEndFlow?()
}
}
func presentRegisterVC(){
let vc1 = storyboard.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
vc1.onRegistration = { [weak self] in
self?.presentViewControllerForCodeInput()
}
self.navigationController?.pushViewController(vc1, animated: true)
}
}

View File

@ -0,0 +1,87 @@
//
// MessagesCoordinator.swift
// GDproject
//
// Created by cstore on 01/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
class MessagesCoordinator: BaseCoordinator {
var didEndSession: (()->())?
let storyboard = UIStoryboard(name: "Main", bundle: nil)
private weak var navigationController: UINavigationController?
init(nc: UINavigationController) {
self.navigationController = nc
}
override func start() {
show()
}
private func show(){
let vc = storyboard.instantiateViewController(withIdentifier: messagesViewControllerId) as! MessagesViewController
// choose person to write message to
vc.onUserDisplayList = { [weak vc, unowned self] in
let newVC = self.storyboard.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
newVC.whatToDoWithSelection = { [weak newVC, weak self] people in
newVC?.navigationController?.popViewController(animated: true)
// detect is it a user or group dialog
let count = people.count
if count == 1 {
let user = people.first!.key
let createdDialog = Model.Dialog.userChat(Model.UserChat(user: user))
let vc = DialogViewController()
vc.users = Model.Channels.fullPeopleDict
vc.dialog = createdDialog
self?.navigationController?.pushViewController(vc, animated: true)
} else {
var group = Model.Group(users: people, name: "Untitled", id: 0)
group.users[DataStorage.standard.getUserId()] = Model.UserPermission(isAdmin: true)
Model.createGroupChat(from: group, completion: { [weak self] id in
let newVC1 = DialogViewController()
group.id = id
newVC1.users = Model.Channels.fullPeopleDict
newVC1.dialog = Model.Dialog.groupChat(Model.GroupChat(group: group))
self?.navigationController?.pushViewController(newVC1, animated: true)
})
}
}
vc?.navigationController?.pushViewController(newVC, animated: true)
}
vc.onDialogDisplay = { [weak vc] in
let newVC = DialogViewController()
newVC.dialog = $0.dialog
newVC.users = $0.users
newVC.onUserDisplay = { [weak self] id in
let vc = self?.storyboard.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
vc.idProfile = id
self?.navigationController!.pushViewController(vc, animated: true)
}
vc?.navigationController?.pushViewController(newVC, animated: true)
}
navigationController?.viewControllers = [vc]
}
}

View File

@ -0,0 +1,60 @@
//
// ProfileCoordinator.swift
// RxSwift
//
// Created by cstore on 02/03/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
class ProfileCoordinator: BaseCoordinator {
var didEndSession: (()->())?
private weak var navigationController: UINavigationController?
init(nc: UINavigationController) {
self.navigationController = nc
}
override func start() {
show()
}
private func show() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let profile = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
profile.logOut = {
Model.logout() {
[weak self] in
DataStorage.standard.setIsLoggedIn(value: false, with: 0)
self?.didEndSession?()
}
}
profile.deleteAllSessions = {
Model.deactivateAll() {
[weak self] in
DataStorage.standard.setIsLoggedIn(value: false, with: 0)
self?.didEndSession?()
}
}
profile.onSettings = { [weak self, weak storyboard, weak profile] in
let vc = storyboard?.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
vc.delegate = profile
vc.userActive = profile?.user
self?.navigationController?.pushViewController(vc, animated: true)
}
navigationController?.setViewControllers([profile], animated: false)
}
}

View File

@ -0,0 +1,50 @@
//
// TabbarController.swift
// RxSwift
//
// Created by cstore on 03/03/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
protocol TabbarView: class {
var onChannelsFlowSelect: ((UINavigationController) -> ())? { get set }
var onProfileFlowSelect: ((UINavigationController) -> ())? { get set }
var onMessagesFlowSelect: ((UINavigationController) -> ())? { get set }
var onViewDidLoad: ((UINavigationController) -> ())? { get set }
}
final class TabbarController: UITabBarController, UITabBarControllerDelegate, TabbarView {
var onChannelsFlowSelect: ((UINavigationController) -> ())?
var onProfileFlowSelect: ((UINavigationController) -> ())?
var onMessagesFlowSelect: ((UINavigationController) -> ())?
var onViewDidLoad: ((UINavigationController) -> ())?
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
if let controller = customizableViewControllers?.first as? UINavigationController {
onViewDidLoad?(controller)
}
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController)
{
guard let controller = viewControllers?[selectedIndex] as? UINavigationController else { return }
if selectedIndex == 0 {
onChannelsFlowSelect?(controller)
} else if selectedIndex == 2 {
onProfileFlowSelect?(controller)
} else {
onMessagesFlowSelect?(controller)
}
}
}

View File

@ -0,0 +1,68 @@
//
// TabBarCoordinator.swift
// RxSwift
//
// Created by cstore on 02/03/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
class TabBarCoordinator: BaseCoordinator {
var didEndFlow: (()->())?
private let tabbarView: TabbarView
private weak var window: UIWindow?
init(tabbarView: TabbarView, window: UIWindow) {
self.tabbarView = tabbarView
self.window = window
}
override func start() {
tabbarView.onViewDidLoad = runChannelsFlow()
tabbarView.onChannelsFlowSelect = runChannelsFlow()
tabbarView.onProfileFlowSelect = runProfileFlow()
tabbarView.onMessagesFlowSelect = runMessagesFlow()
window?.rootViewController = tabbarView as! TabbarController
}
private func runChannelsFlow() -> ((UINavigationController) -> ())
{
return { [unowned self] navController in
if navController.viewControllers.isEmpty == true {
let channelCoordinator = ChannelsCoordinator(nc: navController)
self.addDependency(channelCoordinator)
channelCoordinator.start()
}
}
}
private func runMessagesFlow() -> ((UINavigationController) -> ()){
return { [unowned self] navController in
if navController.viewControllers.isEmpty == true {
let messagesCoordinator = MessagesCoordinator(nc: navController)
self.addDependency(messagesCoordinator)
messagesCoordinator.start()
}
}
}
private func runProfileFlow() -> ((UINavigationController) -> ())
{
return { [unowned self] navController in
if navController.viewControllers.isEmpty == true {
let profileCoordinator = ProfileCoordinator(nc: navController)
profileCoordinator.didEndSession = { [weak self, weak profileCoordinator] in
self?.removeDependency(profileCoordinator)
self?.didEndFlow?()
}
self.addDependency(profileCoordinator)
profileCoordinator.start()
}
}
}
}

View File

@ -0,0 +1,144 @@
//
// CodeViewController.swift
// GDproject
//
// Created by cstore on 10/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
import TinyConstraints
class CodeViewController: UIViewController {
@IBOutlet weak var f1: UITextField!
@IBOutlet weak var f2: UITextField!
@IBOutlet weak var f3: UITextField!
@IBOutlet weak var f4: UITextField!
@IBOutlet weak var f5: UITextField!
@IBOutlet weak var f6: UITextField!
var loading = UIActivityIndicatorView(style: .gray)
var onSuccessLogIn: (()->())?
override func viewDidLoad() {
super.viewDidLoad()
setUpConstraint()
navigationItem.title = DataStorage.standard.getEmail()
f1.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
f2.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
f3.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
f4.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
f5.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
f6.addTarget(self, action: #selector(textFiledDidChange(textField:)), for: .editingChanged)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
loading.stopAnimating()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
f1.becomeFirstResponder()
}
@objc func textFiledDidChange(textField: UITextField) {
let text = textField.text
// only 1 char
if text?.utf16.count == 1 {
switch textField {
case f1:
f2.becomeFirstResponder()
case f2:
f3.becomeFirstResponder()
case f3:
f4.becomeFirstResponder()
case f4:
f5.becomeFirstResponder()
case f5:
f6.becomeFirstResponder()
case f6:
f6.resignFirstResponder()
default:
break
}
}
}
func presentAlertInvalidData(with text: String)
{
let alert = UIAlertController(title: "Invalid code", message: text, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
loading.stopAnimating()
}
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
@IBAction func whereToGoNext(_ sender: UIButton)
{
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 {
presentAlertInvalidData(with: "Some fields are missing");
return
}
if f1t.isEmpty || f2t.isEmpty || f3t.isEmpty || f4t.isEmpty || f5t.isEmpty || f6t.isEmpty {
presentAlertInvalidData(with: "Some fields are missing");
return
}
let code = "\(f1.text!)\(f2.text!)\(f3.text!)\(f4.text!)\(f5.text!)\(f6.text!)"
if let codeToInt = Int(code)
{
loading.startAnimating()
Model.verify(with: codeToInt) { [weak self] in
// if everything is okay we can authemticicate
if !$0 {
self?.presentAlertInvalidData(with: "Wrong code. Try again!")
self?.loading.stopAnimating()
return
} else {
// Model.authemticiateMe
Model.authenticateMe { [weak self] (res) in
if res {
self?.onSuccessLogIn?()
}
}
return
}
}
}
}
func setUpConstraint()
{
self.view.addSubview(loading)
loading.centerInSuperview()
// for keyboard notifications
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func handleKeyboardNotifications(notification: NSNotification){
if let userInfo = notification.userInfo {
// UIKeyboardFrameEndUserInfoKey
let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? keyBoardFrame.height - self.view.safeAreaInsets.bottom : 0
UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
})
}
}
}

View File

@ -0,0 +1,88 @@
//
// FacultyTableViewController.swift
// GDproject
//
// Created by cstore on 10/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
protocol ChosenFactulty: class {
func onChooseFaculty(faculty: Model.Faculty)
}
class FacultyTableViewController: UITableViewController {
weak var delegate: ChosenFactulty?
var currentFaculties: [Model.Faculty] = []{
didSet {
tableView.reloadData()
}
}
var isFiltering: Bool {
return searchController.isActive && !searchBarIsEmpty()
}
func searchBarIsEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
var searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Faculties"
self.navigationItem.searchController = searchController
self.navigationItem.hidesSearchBarWhenScrolling = false
searchController.obscuresBackgroundDuringPresentation = false
setUpTimer()
}
func setUpTimer(){
Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { (timer) in
DispatchQueue.main.async { [weak self] in
if self!.isFiltering {
Model.searchFaculty(string: (self?.searchController.searchBar.text)!) { [weak self] in
self?.currentFaculties = $0
}
}
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentFaculties.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "F", for: indexPath)
cell.textLabel?.text = currentFaculties[indexPath.row].name
cell.detailTextLabel?.text = currentFaculties[indexPath.row].campusName
cell.selectionStyle = .none
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.onChooseFaculty(faculty: currentFaculties[indexPath.row])
searchController.dismiss(animated: true, completion: nil)
self.navigationController?.popViewController(animated: true)
}
}

View File

@ -0,0 +1,23 @@
//
// InititalsViewCell.swift
// GDproject
//
// Created by cstore on 10/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
class InititalsViewCell: UITableViewCell {
@IBOutlet weak var initialsTextField: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func fill(with name: String){
initialsTextField.text = name
}
}

View File

@ -1,48 +0,0 @@
//
// LogInCoordinator.swift
// GDproject
//
// Created by cstore on 23/02/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
class LogInCoordinator{
private weak var navigationController: UINavigationController?
private var window: UIWindow!
// MARK:- Init
init(navigationController: UINavigationController, window: UIWindow) {
self.navigationController = navigationController
self.window = window
}
func start(){
showLogInPage()
}
// MARK: - Private implementation
// private func showStatusPage(){
// let controller = TabbarCoordinator(window: window)
// controller.start()
// }
private func showLogInPage(){
let controller = UIStoryboard.makeLogIn()
controller.onLogIn = {
(id) in Model.authenticate(with: id) {
(res) in
if (res) { DataStorage.standard.setUserKey(with: id) }
else { DataStorage.standard.setUserKey(with: 0) }
controller.authenticateSucceeded = res
}
}
navigationController?.pushViewController(controller, animated: false)
}
}

View File

@ -1,128 +1,135 @@
//
// LogInViewController.swift
// NewsFeed
// RxSwift
//
// Created by cstore on 20/01/2019.
// Created by cstore on 01/03/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
import TinyConstraints
import ReactiveSwift
import ReactiveCocoa
import Result
class LogInViewController: UIViewController {
@IBOutlet weak var mailTextField: UITextField!
var loading = UIActivityIndicatorView(style: .gray)
@IBOutlet weak var indicatorView: UIActivityIndicatorView!
var authenticate: ((String)->())?
var onLogIn: ((Int)->())?
var authenticateSucceeded: Bool? {
didSet {
if !authenticateSucceeded! {
indicatorView.stopAnimating()
indicatorView.isHidden = true
}
}
}
static let titleColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)
var bottomConstraint: NSLayoutConstraint?
let logInButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Log In", for: .normal)
button.setTitleColor(titleColor, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.isEnabled = false
button.addTarget(self, action: #selector(activateLogInProcess), for: .touchUpInside)
return button
}()
let keyboardBar: UIView = {
let view = UIView()
view.backgroundColor = .white
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
setUpView()
configureTapgesture()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
func presentAlertInvalidCode()
{
let alert = UIAlertController(title: "Invalid email", message: "Try again. Use @hse.ru mail.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
mailTextField.text = ""
loading.stopAnimating()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
loading.stopAnimating()
}
private func configureTapgesture(){
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
view.addGestureRecognizer(tapGesture)
}
let logInLabel: UILabel = {
let label = UILabel()
label.text = "Log In"
label.textColor = .black
label.font = UIFont.boldSystemFont(ofSize: 34)
return label
}()
let mailTextField: UITextField = {
let textField = UITextField()
textField.backgroundColor = #colorLiteral(red: 0.937254902, green: 0.937254902, blue: 0.9568627451, alpha: 1)
textField.placeholder = "Mail"
textField.borderStyle = .roundedRect
textField.textColor = .black
textField.autocorrectionType = UITextAutocorrectionType.no
textField.autocapitalizationType = UITextAutocapitalizationType.none
textField.clearButtonMode = .always
return textField
}()
let logInButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Log In", for: .normal)
button.setTitleColor(blueSystemColor, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.addTarget(self, action: #selector(handleTap), for: .touchUpInside)
button.isEnabled = false
return button
}()
@objc func handleTap(){
view.endEditing(true)
loading.startAnimating()
authenticate?(mailTextField.text!)
}
@objc func activateLogInProcess(){
if logInButton.isEnabled {
// MARK:- when log in is succeeded do I need to go there?
if let id = Int(mailTextField.text!){
indicatorView.isHidden = false
indicatorView.startAnimating()
onLogIn?(id)
view.endEditing(true)
} else {
logInButton.isEnabled = false
logInButton.setTitleColor(LogInViewController.titleColor.withAlphaComponent(0.5), for: .normal)
}
}
}
private lazy var keyboardBar = UIView()
private lazy var contentView = UIView()
private var bottomConstraint: NSLayoutConstraint?
func setUpView(){
indicatorView.isHidden = true
mailTextField.delegate = self
view.addSubview(keyboardBar)
// logIn stack with textField and label
view.addSubview(contentView)
view.addSubview(loading)
view.addConstraintsWithFormat(format: "H:|[v0]|", views: keyboardBar)
view.addConstraintsWithFormat(format: "V:[v0(50)]", views: keyboardBar)
loading.centerInSuperview()
setUpBarComponents()
configureKeyboardBehavior()
contentView.edgesToSuperview(excluding: .bottom, insets: .left(16) + .right(16) + .top(80), usingSafeArea: true)
let views = [logInLabel, mailTextField]
contentView.stack(views, axis: .vertical, spacing: 10)
}
func configureKeyboardBehavior(){
func configureKeyboard(){
mailTextField.keyboardType = .emailAddress
// configure keyboardBar setUp
view.addSubview(keyboardBar)
keyboardBar.height(50)
keyboardBar.edgesToSuperview(excluding: [.top,.bottom])
bottomConstraint = NSLayoutConstraint(item: keyboardBar, attribute: .bottom, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
view.addConstraint(bottomConstraint!)
// configure keyboardBar components
keyboardBar.addSubview(logInButton)
logInButton.height(50)
logInButton.rightToSuperview(view.rightAnchor, offset: -16, relation: .equal, isActive: true)
}
func logicOfLogInInputValidation() -> ((String?)->()) {
let logic: ((String?)->()) = { [weak self] (someText) in
if let text = someText, !text.isEmpty, text.contains("@") {
self?.logInButton.isEnabled = true
} else {
self?.logInButton.isEnabled = false
}
}
return logic
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
setUpView()
configureKeyboard()
let mailFieldValuesSignal: Signal<String, NoError> = mailTextField.reactive.continuousTextValues
mailFieldValuesSignal.observeValues(logicOfLogInInputValidation())
// for keyboard notifications
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
// for log in button notifications
NotificationCenter.default.addObserver(self, selector: #selector(inputDidChanged), name: UITextField.textDidChangeNotification, object: mailTextField)
NotificationCenter.default.addObserver(self, selector: #selector(inputDidChanged), name: UITextField.textDidBeginEditingNotification, object: mailTextField)
}
@objc func inputDidChanged(notification: NSNotification){
if mailTextField.text?.isEmpty ?? true
{
logInButton.isEnabled = false
logInButton.setTitleColor(LogInViewController.titleColor.withAlphaComponent(0.5), for: .normal)
}
else
{
logInButton.isEnabled = true
logInButton.setTitleColor(LogInViewController.titleColor.withAlphaComponent(1), for: .normal)
}
}
@objc func handleKeyboardNotifications(notification: NSNotification){
if let userInfo = notification.userInfo{
@ -136,18 +143,13 @@ class LogInViewController: UIViewController {
}
}
func setUpBarComponents(){
keyboardBar.addSubview(logInButton)
keyboardBar.addConstraintsWithFormat(format: "H:[v0(60)]-16-|", views: logInButton)
keyboardBar.addConstraintsWithFormat(format: "V:|[v0]|", views: logInButton)
}
}
extension LogInViewController: UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool
{
textField.resignFirstResponder()
return true
extension UIButton {
override open var isEnabled: Bool {
didSet {
let color = isEnabled ? self.titleLabel?.textColor.withAlphaComponent(1) : self.titleLabel?.textColor.withAlphaComponent(0.5)
self.setTitleColor(color, for: .normal)
}
}
}

View File

@ -0,0 +1,198 @@
//
// RegisterTableViewController.swift
// GDproject
//
// Created by cstore on 10/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
class RegisterTableViewController: UITableViewController, ChosenFactulty
{
func presentAlertInvalidData(message: String)
{
let alert = UIAlertController(title: "Invalid data", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
func onChooseFaculty(faculty: Model.Faculty) {
self.faculty = faculty
tableView.reloadData()
}
weak var delegate: UpdateUser?
var onRegistration: (()->())?
var faculty: Model.Faculty?
var user: Model.NewRegistration = Model.NewRegistration(email: DataStorage.standard.getEmail()!, firstName: nil, middleName: nil, lastName: nil, faculty: nil)
var userActive: Model.Users? {
didSet {
if let userA = userActive {
user.firstName = userA.firstName
user.middleName = userA.middleName
user.lastName = userA.lastName
faculty = userA.faculty
self.updateUserIfCan = true
tableView.reloadData()
}
}
}
var updateUserIfCan: Bool = false
override func viewDidLoad()
{
super.viewDidLoad()
navigationItem.largeTitleDisplayMode = .never
tableView.keyboardDismissMode = .interactive
navigationItem.title = user.email
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(endRegistration))
}
@objc func endRegistration()
{
let fieldsMissing = "Some fields are missing. Add more information"
updateUser()
guard let faculty = faculty else { presentAlertInvalidData(message: fieldsMissing); return }
user.faculty = faculty.url
guard let name = user.firstName else { presentAlertInvalidData(message: fieldsMissing); return }
guard let middle = user.middleName else { presentAlertInvalidData(message: fieldsMissing); return }
guard let last = user.lastName else { presentAlertInvalidData(message: fieldsMissing); return }
if updateUserIfCan {
guard let delegate = delegate else { return }
guard var userA = userActive else { return }
// updating current
userA.firstName = name
userA.faculty = faculty
userA.middleName = middle
userA.lastName = last
Model.userUpdate(with: user) { [weak self] in
if $0 {
delegate.updateUserObj(with: userA)
self?.navigationController?.popViewController(animated: true)
} else {
self?.presentAlertInvalidData(message: "Something went wrong! Try again")
}
}
} else {
Model.register(object: user)
{ [weak self] in
self?.onRegistration?()
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 3
default:
if let _ = faculty {
return 2
} else {
return 1
}
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
switch section {
case 0:
return "Initials"
default:
return "Faculty"
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! InititalsViewCell
switch indexPath.row{
case 0:
if let name = user.firstName {
cell.fill(with: name)
} else {
cell.initialsTextField.placeholder = "First name"
}
case 1:
if let name = user.middleName {
cell.fill(with: name)
} else {
cell.initialsTextField.placeholder = "Middle name"
}
default:
if let name = user.lastName {
cell.fill(with: name)
} else {
cell.initialsTextField.placeholder = "Last name"
}
}
cell.selectionStyle = .none
return cell
default:
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell111", for: indexPath)
cell.selectionStyle = .none
return cell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "facultyCell", for: indexPath)
cell.textLabel?.text = faculty!.name
cell.detailTextLabel?.text = faculty!.campusName
cell.selectionStyle = .none
return cell
}
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 1 && indexPath.row == 0 {
updateUser()
let vc = storyboard?.instantiateViewController(withIdentifier: "FacultyTableViewController") as! FacultyTableViewController
vc.delegate = self
self.navigationController?.pushViewController(vc, animated: true)
}
}
func updateUser(){
guard let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as? InititalsViewCell else {return}
guard let cell1 = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? InititalsViewCell else {return}
guard let cell2 = tableView.cellForRow(at: IndexPath(row: 2, section: 0)) as? InititalsViewCell else {return}
user.firstName = cell.initialsTextField.text!
user.middleName = cell1.initialsTextField.text!
user.lastName = cell2.initialsTextField.text!
}
}

View File

@ -0,0 +1,308 @@
//
// ChatInfoViewController.swift
// GDproject
//
// Created by cstore on 02/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
/// Class for displaying chat info
///
class ChatInfoViewController: UITableViewController {
enum PersonStatus{
case admin
case ordinary
}
weak var delegate: UpdatableGroup?
var groupChat: Model.Group? {
didSet{
if let groupChat = groupChat {
usersArray = groupChat.users.map { $0.key }
}
}
}
var usersArray: [Int] = [] {
didSet {
tableView.reloadData()
}
}
var users: [Int: Model.Users] = [:]
func canIEditThisChat() -> PersonStatus
{
let myId = UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
if let groupChatUserPermission = groupChat?.users[myId]?.isAdmin {
return groupChatUserPermission ? .admin : .ordinary
}
return .ordinary
}
var myPermissions: PersonStatus = .ordinary
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
myPermissions = canIEditThisChat()
tableView.reloadData()
switch myPermissions {
case .admin:
navigationItem.rightBarButtonItem = self.editButtonItem
default:
return
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 1
case 1:
return 1
default:
return usersArray.count + (myPermissions == .ordinary ? 0 : 1)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if indexPath.row == 0 {
switch indexPath.section {
case 0:
cell.textLabel?.text = groupChat!.name
cell.selectionStyle = .none
return cell
case 1:
cell.textLabel?.text = "Leave chat"
cell.textLabel?.textColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
cell.selectionStyle = .none
return cell
default:
switch myPermissions{
case .admin:
cell.textLabel?.text = "Add participants"
cell.accessoryType = .disclosureIndicator
case .ordinary:
cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
}
cell.selectionStyle = .none
return cell
}
}
switch myPermissions{
case .admin:
cell.textLabel?.text = name(for: users[usersArray[indexPath.row-1]])
case .ordinary:
cell.textLabel?.text = name(for: users[usersArray[indexPath.row]])
}
cell.selectionStyle = .none
return cell
}
private func name(for user: Model.Users?) -> String {
if let user = user, let perm = groupChat?.users[user.id]?.isAdmin {
if perm {
return "🤴🏻 \(user.fullName())"
}
return "👤 \(user.fullName())"
}
return "left"
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
switch section {
case 0:
return "Title"
case 1:
return "Opportunities"
default:
return "Participants"
}
}
func editName(for cell: UITableViewCell){
let alert = UIAlertController(title: "Are you sure?", message: "Title:", preferredStyle: .alert)
let action1 = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addTextField { [weak self] (tf) in
tf.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
tf.text = self?.groupChat?.name
}
let action2 = UIAlertAction(title: "OK", style: .default) { [unowned self] _ in
let name = alert.textFields?.first?.text
cell.textLabel?.text = name
self.groupChat?.name = name!
Model.updateGroupChat(with: self.groupChat!)
self.delegate?.updateGroup(with: self.groupChat!)
}
alert.addAction(action1)
alert.addAction(action2)
present(alert, animated: true, completion: nil)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
guard let groupChat = groupChat else {
return
}
guard let cell = tableView.cellForRow(at: indexPath) else {
return
}
if indexPath.row == 0 {
switch indexPath.section{
case 0:
switch myPermissions{
case .admin:
editName(for: cell)
default:
break
}
case 1:
Model.leaveGroupChat(id: groupChat.id) {
[weak self] in
self?.navigationController?.popViewController(animated: true)
}
default:
switch myPermissions{
case .admin:
showUserChoiceVC()
default:
showParticipantPage(with: usersArray[indexPath.row])
}
}
}
if indexPath.section == 2 && indexPath.row != 0 {
switch myPermissions{
case .admin:
showParticipantPage(with: usersArray[indexPath.row-1])
default:
showParticipantPage(with: usersArray[indexPath.row])
}
}
}
var onUserDiplay: ((Int)->())?
func showParticipantPage(with user: Int?) {
if let user = user {
onUserDiplay?(user)
}
}
func showUserChoiceVC()
{
let vc = storyboard?.instantiateViewController(withIdentifier: peopleToWriteVC) as! PeopleToWriteViewController
vc.whatToDoWithSelection = { [weak self, weak vc] mapa in
mapa.forEach { self?.users[$0.key] = Model.Channels.fullPeopleDict[$0.key] }
mapa.forEach { self?.groupChat?.users[$0.key] = $0.value }
vc?.navigationController?.popViewController(animated: true)
}
navigationController?.pushViewController(vc, animated: true)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == UITableViewCell.EditingStyle.delete {
groupChat?.users[usersArray[indexPath.row-1]] = nil
}
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
if indexPath.row == 0 {
return false
}
return true
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
{
let editButton = UITableViewRowAction(style: .normal, title: "Promote") { [unowned self] (rowAction, indexPath) in
self.tableView.beginUpdates()
self.groupChat?.users[self.usersArray[indexPath.row-1]]?.isAdmin = true
self.tableView.reloadRows(at: [indexPath], with: .none)
self.tableView.endUpdates()
}
editButton.backgroundColor = #colorLiteral(red: 0.476841867, green: 0.5048075914, blue: 1, alpha: 1)
let restrictButton = UITableViewRowAction(style: .normal, title: "Restrict") { [unowned self] (rowAction, indexPath) in
self.tableView.beginUpdates()
self.groupChat?.users[self.usersArray[indexPath.row-1]]?.isAdmin = false
self.tableView.reloadRows(at: [indexPath], with: .none)
self.tableView.endUpdates()
}
restrictButton.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
let deleteButton = UITableViewRowAction(style: .normal, title: "Delete") { [unowned self] (action, indexPath) in
self.tableView.beginUpdates()
self.groupChat?.users[self.usersArray[indexPath.row-1]] = nil
self.tableView.deleteRows(at: [indexPath], with: .none)
self.tableView.endUpdates()
}
deleteButton.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
return [editButton, restrictButton, deleteButton]
}
/// update chatInfo
override func viewWillDisappear(_ animated: Bool) {
defer {
super.viewWillDisappear(animated)
}
guard let _ = self.navigationController?.viewControllers.lastIndex(of: self) else {
switch myPermissions {
case .ordinary:
return
case .admin:
Model.updateGroupChat(with: groupChat!)
delegate?.updateGroup(with: groupChat!)
}
return
}
}
}

View File

@ -0,0 +1,132 @@
//
// DialogCell.swift
// GDproject
//
// Created by cstore on 05/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
import TinyConstraints
import MarkdownKit
class DialogCell: UITableViewCell {
let nameLabel: UIButton = {
let button = UIButton()
button.setTitleColor(.black, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.left
return button
}()
@objc func displayProfile()
{
if let id = self.user?.id {
print("diplay")
onUserDisplay?(id)
}
}
var onUserDisplay: ((Int)->())?
let timeLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 9)
label.textAlignment = NSTextAlignment.right
label.textColor = #colorLiteral(red: 0.4352941176, green: 0.4431372549, blue: 0.4745098039, alpha: 1)
return label
}()
func createTextView(with text: NSAttributedString, _ isSelectable: Bool) -> UITextView
{
let textView = UITextView()
textView.isScrollEnabled = false
textView.isEditable = false
textView.sizeToFit()
if isSelectable {
textView.isSelectable = true
} else {
textView.isUserInteractionEnabled = false
}
textView.attributedText = text
return textView
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
{
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
var user: Model.Users? {
didSet{
nameLabel.setTitle(user!.fullName(), for: .normal)
}
}
var textView: UITextView!
func fill(with markdownText: NSAttributedString, byUser: Model.Users, when: String)
{
let myId = DataStorage.standard.getUserId()
// important
contentView.subviews.forEach({ $0.removeFromSuperview() })
nameLabel.addTarget(self, action: #selector(displayProfile), for: .touchUpInside)
self.user = byUser
textView = createTextView(with: markdownText, true)
textView.layer.cornerRadius = 10
textView.clipsToBounds = true
self.contentView.addSubview(textView)
self.contentView.addSubview(timeLabel)
timeLabel.text = when.getDate()
textView.width(min: 50, max: self.contentView.bounds.width-70, priority: .required, isActive: true)
if myId == byUser.id
{
layoutMyMessage()
} else {
layOutOtherMessage()
}
}
func layOutOtherMessage(){
self.contentView.addSubview(nameLabel)
nameLabel.setTitle(user!.fullName(), for: .normal)
nameLabel.edgesToSuperview(excluding: .bottom, insets: .top(4) + .left(8))
textView.edgesToSuperview(excluding: [.top, .right] , insets: .left(8) + .bottom(20))
textView.topToBottom(of: nameLabel)
textView.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
textView.textColor = .white
timeLabel.edgesToSuperview(excluding: .top, insets: .right(70) + .left(8))
timeLabel.topToBottom(of: textView, offset: 4)
timeLabel.textAlignment = .left
}
func layoutMyMessage()
{
textView.edgesToSuperview(excluding: .left, insets: .right(8) + .bottom(20) + .top(4))
textView.backgroundColor = UIColor(red:0.08, green:0.49, blue:0.98, alpha:1.0)
textView.textColor = .white
timeLabel.edgesToSuperview(excluding: .top, insets: .left(70) + .right(8))
timeLabel.topToBottom(of: textView, offset: 4)
timeLabel.textAlignment = .right
}
}

View File

@ -0,0 +1,340 @@
//
// DialogViewController.swift
// GDproject
//
// Created by cstore on 01/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
import TinyConstraints
import Marklight
protocol UpdatableGroup:class {
func updateGroup(with group: Model.Group)
}
class DialogViewController: UIViewController, UpdatableGroup, UITableViewDelegate, UITableViewDataSource
{
var onUserDisplay: ((Int)->())?
var tableView: UITableView = UITableView()
func updateGroup(with group: Model.Group){
self.groupChat?.group = group
setTitleForGroup(groupChat: groupChat!)
}
let cellId = "cell3"
var onInfoShow: (()->())?
var dialog: Model.Dialog? {
didSet{
switch dialog! {
case .groupChat(let chat):
self.groupChat = chat
case .userChat(let chat):
self.userChat = chat
}
}
}
var groupChat: Model.GroupChat?
var userChat: Model.UserChat?
var users: [Int: Model.Users]?
var groupId: Int?
var cellData: [PostCellData] = [] {
didSet {
tableView.reloadData()
canBePaginated = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
setConstraints()
magicForKeyboardChanges()
self.tableView.delegate = self
self.tableView.dataSource = self
tableView.setContentOffset(CGPoint(x: 0, y: 50), animated: false)
navigationItem.largeTitleDisplayMode = .never
tableView.keyboardDismissMode = .onDrag
tableView.separatorStyle = .none
tableView.register(DialogCell.self, forCellReuseIdentifier: cellId)
tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
tableView.contentInsetAdjustmentBehavior = .never
tableView.contentOffset = CGPoint(x: 0, y: 30)
if let groupChat = groupChat {
setTitleForGroup(groupChat: groupChat)
} else if let userChat = userChat{
setTitleForChat(userChat: userChat)
}
}
var messageSendView: UIView = {
let view = UIView()
view.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
return view
}()
var messageTextView: UITextView =
{
let textStorage = MarklightTextStorage()
textStorage.marklightTextProcessor.codeColor = UIColor.orange
textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
textStorage.marklightTextProcessor.codeFontName = "Courier"
textStorage.marklightTextProcessor.fontTextStyle = UIFont.TextStyle.subheadline.rawValue
textStorage.marklightTextProcessor.hideSyntax = false
let layoutManager = NSLayoutManager()
// Assign the `UITextView`'s `NSLayoutManager` to the `NSTextStorage` subclass
//textStorage.addLayoutManager(textView.layoutManager)
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer()
layoutManager.addTextContainer(textContainer)
let textView = UITextView(frame: CGRect.zero, textContainer: textContainer)
textView.isEditable = true
textView.isScrollEnabled = true
textView.backgroundColor = .white
return textView
}()
var sendButton: UIButton = {
let button = UIButton()
button.setTitle("Send", for: .normal)
button.setTitleColor(.blue, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
button.addTarget(self, action: #selector(sendMessage), for: .touchUpInside)
return button
}()
@objc func sendMessage()
{
var destination: Model.MessageDestination?
if let group = groupChat {
destination = Model.MessageDestination.groupChatDestination(group.group.id)
} else if let user = userChat {
destination = Model.MessageDestination.userChatDestination(user.user)
}
if let destination = destination
{
Model.sendMessage(message: Model.SendMessage(body: Model.Attachments(markdown: messageTextView.text), destination: destination)) { [unowned self] in
switch $0 {
case .success, .success1:
self.getMessagesNew(for: self.dialog!)
self.messageTextView.text = ""
default:
self.showAlertOn(result: $0)
}
}
prevLast = -1
}
}
var lineView: UIView = {
let view = UIView()
view.backgroundColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
return view
}()
var bottomConstraint: NSLayoutConstraint!
func setConstraints(){
self.view.addSubview(tableView)
self.view.addSubview(messageSendView)
messageSendView.addSubview(messageTextView)
messageSendView.addSubview(sendButton)
messageSendView.addSubview(lineView)
messageSendView.edgesToSuperview(excluding: [.top,.bottom])
bottomConstraint = NSLayoutConstraint(item: messageSendView, attribute: .bottom, relatedBy: .equal, toItem: self.view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
view.addConstraint(bottomConstraint)
messageSendView.height(60)
sendButton.edgesToSuperview(excluding: .left)
sendButton.width(60)
lineView.edgesToSuperview(excluding: .bottom)
lineView.height(0.5)
messageTextView.edgesToSuperview(excluding: .right)
messageTextView.rightToLeft(of: sendButton)
tableView.edgesToSuperview(excluding: .bottom)
tableView.bottomToTop(of: messageSendView)
self.view.layoutSubviews()
}
func magicForKeyboardChanges()
{
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func handleKeyboardNotifications(notification: NSNotification){
if let userInfo = notification.userInfo{
// UIKeyboardFrameEndUserInfoKey
let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
bottomConstraint.constant = notification.name == UIResponder.keyboardWillShowNotification ? -(keyBoardFrame.height) + self.view.safeAreaInsets.bottom : 0
UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}) { (completed) in
}
}
}
func setTitleForChat(userChat: Model.UserChat){
navigationItem.title = "\(users![userChat.user]!.fullName())"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "👤", style: .plain, target: self, action: #selector(showPersonPage))
}
@objc func showPersonPage(){
if let id = userChat?.user{
onUserDisplay?(id)
}
}
func setTitleForGroup(groupChat: Model.GroupChat){
navigationItem.title = "\(groupChat.group.name)"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Info", style: .plain, target: self, action: #selector(moveToInfoVC))
}
// onInfoShow
@objc func moveToInfoVC(){
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: chatInfoViewController) as! ChatInfoViewController
vc.delegate = self
vc.users = users!
vc.onUserDiplay = onUserDisplay
if let groupChat = groupChat {
vc.groupChat = groupChat.group
}
navigationController?.pushViewController(vc, animated: true)
}
var currentMessagesInChat: [Model.LastMessage] = [] {
didSet
{
cellData = currentMessagesInChat.map { PostCellData(attributedData: PostCellData.create(with: [$0.body])) }
}
}
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellData.count
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
tabBarController?.tabBar.isHidden = true
if let dialog = dialog {
getMessagesNew(for: dialog)
}
}
func getMessages(for dialog: Model.Dialog, starting from: Int? = nil)
{
switch dialog {
case .groupChat(let groupChat):
Model.getMessagesFor(typeOfChat: Model.Dialog.groupChat(groupChat), chat: groupChat.group.id, exclusiveFrom: from)
{ [weak self] in
self?.currentMessagesInChat.append(contentsOf: $0)
}
case .userChat(let userChat):
Model.getMessagesFor(typeOfChat: Model.Dialog.userChat(userChat), chat: userChat.user, exclusiveFrom: from)
{ [weak self] in
self?.currentMessagesInChat.append(contentsOf: $0)
}
}
}
func getMessagesNew(for dialog: Model.Dialog, starting from: Int? = nil)
{
switch dialog {
case .groupChat(let groupChat):
Model.getMessagesFor(typeOfChat: Model.Dialog.groupChat(groupChat), chat: groupChat.group.id, exclusiveFrom: from)
{ [weak self] in
self?.currentMessagesInChat = $0
}
case .userChat(let userChat):
Model.getMessagesFor(typeOfChat: Model.Dialog.userChat(userChat), chat: userChat.user, exclusiveFrom: from)
{ [weak self] in
self?.currentMessagesInChat = $0
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! DialogCell
//In cellForRowAtIndexPath
cell.transform = CGAffineTransform(scaleX: 1, y: -1)
cell.selectionStyle = .none
if let user = users?[currentMessagesInChat[indexPath.row].author]
{
cell.fill(with: cellData[indexPath.row].attributedData, byUser: user, when: currentMessagesInChat[indexPath.row].time)
cell.onUserDisplay = onUserDisplay
}
return cell
}
var prevLast = -1
var canBePaginated = false
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
if indexPath.row == cellData.count - 1 && prevLast != indexPath.row && canBePaginated && cellData.count >= 24
{
print("exclusiveFrom \(currentMessagesInChat.last?.id ?? 0)")
if let dialog = dialog
{
getMessages(for: dialog, starting: currentMessagesInChat.last?.id)
}
prevLast = indexPath.row
}
}
}

View File

@ -0,0 +1,38 @@
//
// MessageViewCell.swift
// GDproject
//
// Created by cstore on 13/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
class MessageViewCell: UITableViewCell {
@IBOutlet weak var dialogName: UILabel!
@IBOutlet weak var lastMessagePreview: UILabel!
@IBOutlet weak var dateLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func fill(with dialog: Model.Dialog, user: Model.Users? = nil)
{
switch dialog {
case .groupChat(let group):
dialogName.text = group.group.name
lastMessagePreview.text = group.lastMessage?.body.markdown
dateLabel.text = group.lastMessage?.time.getDate()
case .userChat(let userChat):
dialogName.text = "👤 \(user!.fullName())"
lastMessagePreview.text = userChat.lastMessage?.body.markdown
dateLabel.text = userChat.lastMessage?.time.getDate()
}
}
}

View File

@ -0,0 +1,181 @@
//
// MessagesViewController.swift
// GDproject
//
// Created by cstore on 01/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
protocol SelectableDialog: class {
func openDialog(with dialog: Model.Dialog)
}
class MessagesViewController: UITableViewController, UISearchControllerDelegate, UISearchResultsUpdating, SelectableDialog {
func openDialog(with dialog: Model.Dialog) {
onDialogDisplay?((dialog, users))
}
func updateSearchResults(for searchController: UISearchController) {
let filteredData = currentActiveDialogs
let inputText = searchController.searchBar.text ?? ""
let filteredResults = filteredData.filter {
switch $0 {
case .groupChat(let gropuChat):
return gropuChat.group.name.contains(inputText)
case .userChat(let userChat):
let user = users[userChat.user]
guard let u = user else { return false }
return u.fullName().contains(inputText)
}
}
// Apply the filtered results to the search results table.
if let resultsController = searchController.searchResultsController as? SuggestedDialogsTableViewController {
resultsController.users = users
resultsController.currentDialogs = filteredResults
resultsController.tableView.reloadData()
}
}
// curreent Active which can be displayed
var currentActiveDialogs: [Model.Dialog] = [] {
didSet {
tableView.reloadData()
}
}
func setUpSearchContr(){
searchController?.delegate = self
searchController?.obscuresBackgroundDuringPresentation = true
navigationItem.searchController = searchController
definesPresentationContext = true
searchController?.searchResultsUpdater = self
searchController?.searchBar.placeholder = "Search dialogs"
}
// curreent users
var users: [Int: Model.Users] = [:]
var onUserDisplayList: (()->())?
var onDialogDisplay: (((dialog: Model.Dialog, users: [Int:Model.Users]))->())?
var searchController: UISearchController?
override func viewDidLoad() {
super.viewDidLoad()
let updater = SuggestedDialogsTableViewController()
updater.delegate = self
searchController = UISearchController(searchResultsController: updater)
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Write", style: .plain, target: self, action: #selector(choosePerson))
self.navigationItem.title = "Messages"
// self.navigationItem.largeTitleDisplayMode = .always
setUpSearchContr()
navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.hidesSearchBarWhenScrolling = false
}
@objc func choosePerson(){
onUserDisplayList?()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tabBarController?.tabBar.isHidden = false
Model.getChatAll { [weak self] in
self?.currentActiveDialogs = $0.0
self?.users = $0.1
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentActiveDialogs.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "MessageViewCell", for: indexPath) as! MessageViewCell
switch currentActiveDialogs[indexPath.row].self {
case .groupChat:
cell.fill(with: currentActiveDialogs[indexPath.row])
case .userChat(let userChat):
cell.fill(with: currentActiveDialogs[indexPath.row], user: users[userChat.user])
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let tuple = (currentActiveDialogs[indexPath.row],users)
onDialogDisplay?(tuple)
}
}
class SuggestedDialogsTableViewController: UITableViewController {
var idCell = "cell"
var users: [Int: Model.Users] = [:]
weak var delegate: SelectableDialog?
var currentDialogs: [Model.Dialog] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: idCell)
tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentDialogs.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: idCell, for: indexPath)
switch currentDialogs[indexPath.row] {
case .groupChat(let groupChat):
cell.textLabel?.text = groupChat.group.name
case .userChat(let userChat):
cell.textLabel?.text = users[userChat.user]?.fullName()
}
cell.accessoryType = .disclosureIndicator
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.openDialog(with: currentDialogs[indexPath.row])
// self.dismiss(animated: true)
}
}

View File

@ -0,0 +1,67 @@
//
// PeopleToWriteViewController.swift
// GDproject
//
// Created by cstore on 01/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import UIKit
class PeopleToWriteViewController: UITableViewController {
// TODO: - edit button when it's used for selection
var whatToDoWithSelection: (([Int: Model.UserPermission])->())?
let searchC = UISearchController(searchResultsController: nil)
let users = Model.Channels.fullPeople
var chosenUsers: [Int: Model.UserPermission] = [:]
override func viewDidLoad() {
super.viewDidLoad()
tableView.isEditing = true
self.navigationItem.title = "People"
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(newMessage))
self.navigationItem.largeTitleDisplayMode = .never
self.navigationItem.searchController = searchC
self.navigationItem.hidesSearchBarWhenScrolling = false
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(true, animated: animated)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
chosenUsers[users[indexPath.row].id] = Model.UserPermission(isAdmin: false)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "peopleToWriteCell", for: indexPath)
cell.textLabel?.text = users[indexPath.row].fullName()
return cell
}
@objc func newMessage()
{
if chosenUsers.count != 0
{
whatToDoWithSelection?(chosenUsers)
}
}
}

View File

@ -16,17 +16,20 @@ struct CellData{
class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var dataSourse: [CellData] = [
CellData(opened: false, title: "Phone", sectionData: ["+7 901 733 01 79"]),
CellData(opened: false, title: "Mail", sectionData: ["vbogomazova@edu.hse.ru"]),
CellData(opened: false, title: "Research ID", sectionData: ["4567834336789456737"]),
CellData(opened: false, title: "Published", sectionData: ["Это будет очень длинное название книги 1, чтобы сделать проверку", "Книга 2", "Книга 3"]),
CellData(opened: false, title: "Courses", sectionData: ["Курс 1", "Курс 2"]),
CellData(opened: false, title: "Link", sectionData: ["https://wwww.hse.ru"])
]
var userInfo: Model.Users? {
didSet {
if let userInfo = userInfo {
dataSourse = [CellData(opened: false, title: "Contacts", sectionData: [userInfo.email, userInfo.faculty.address]),
CellData(opened: false, title: "Faculty", sectionData: [userInfo.faculty.campusName, userInfo.faculty.name, userInfo.faculty.address, userInfo.faculty.path]),
CellData(opened: false, title: "Interests", sectionData: userInfo.faculty.tags)]
}
}
}
var dataSourse: [CellData] = [ ]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (dataSourse[section].opened){
if (dataSourse[section].opened) {
return dataSourse[section].sectionData.count + 1
} else {
return 1
@ -45,8 +48,10 @@ class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDat
cell.selectionStyle = .none
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = dataSourse[indexPath.section].sectionData[indexPath.row - 1]
let cell = tableView.dequeueReusableCell(withIdentifier: infoCellId, for: indexPath) as! InfoCell
cell.fill(title: dataSourse[indexPath.section].sectionData[indexPath.row - 1])
cell.accessoryType = .none
cell.selectionStyle = .none
return cell
}
}

View File

@ -16,8 +16,9 @@ class InfoCell: UITableViewCell{
label.font = UIFont.systemFont(ofSize: 16)
label.sizeToFit()
label.isScrollEnabled = false
label.isUserInteractionEnabled = false
// label.isUserInteractionEnabled = false
label.isEditable = false
label.dataDetectorTypes = .all
label.textColor = .black
return label
}()

View File

@ -9,8 +9,17 @@
import UIKit
import TinyConstraints
class ProfileViewController: UIViewController
protocol UpdateUser: class {
func updateUserObj(with user: Model.Users)
}
class ProfileViewController: UIViewController, UpdateUser
{
func updateUserObj(with user: Model.Users)
{
self.user = user
Model.Channels.fullPeopleDict[user.id] = user
}
@IBOutlet weak var segmentedControl: UISegmentedControl!
@ -30,14 +39,33 @@ class ProfileViewController: UIViewController
@IBOutlet weak var newMessageButton: UIButton!
var protoDictionary: [Int: UIImage] = [9: #imageLiteral(resourceName: "9"), 5051: #imageLiteral(resourceName: "5051"), 69: #imageLiteral(resourceName: "69"), 42: #imageLiteral(resourceName: "42")]
var logOut: (()->())?
func fill(with user: Model.Users){
self.facultyLabel.text = "Студент: Факультет Компьютерных Наук"
var deleteAllSessions: (()->())?
var onSettings: (()->())?
@IBAction func sendMessage(_ sender: UIButton)
{
if let userId = idProfile
{
let createdDialog = Model.Dialog.userChat(Model.UserChat(user: userId))
let vc = DialogViewController()
vc.users = Model.Channels.fullPeopleDict
vc.dialog = createdDialog
self.navigationController?.pushViewController(vc, animated: true)
}
}
var protoDictionary: [String: UIImage] = ["135213": #imageLiteral(resourceName: "9"), "135288": #imageLiteral(resourceName: "5051"), "22723" : #imageLiteral(resourceName: "69"), "135083": #imageLiteral(resourceName: "42")]
func fill(with user: Model.Users)
{
self.facultyLabel.text = user.faculty.name
self.nameLabel.text = "\(user.firstName) \(user.middleName)"
self.surnameLabel.text = "\(user.lastName)"
self.profileImageView.image = protoDictionary[user.id]?.roundedImage
self.placeLabel.text = "📍Москва, Кочновский пр.3"
self.profileImageView.image = protoDictionary[user.faculty.campusCode]?.roundedImage
self.placeLabel.text = "📍\(user.faculty.address)"
if user.id == DataStorage.standard.getUserId() {
newMessageButton.isHidden = true
} else {
@ -47,46 +75,61 @@ class ProfileViewController: UIViewController
var user: Model.Users? {
didSet {
self.fill(with: user!)
Model.getPostsForUser(with: user!.id) { [weak self] (posts) in
self?.dataSourse = posts
if let user = user {
self.fill(with: user)
navigationItem.title = "\(user.firstName) \(user.lastName)"
} else if let id = idProfile {
Model.getUsers(for: [id]) { [unowned self ] in
self.user = $0[id]
}
}
navigationItem.title = "\(user!.firstName) \(user!.lastName)"
}
}
var channel: Model.Channels? {
didSet {
self.update()
}
}
func update()
{
Model.getAnonymousChannel(by: channel!) { [unowned self] in
self.posts.dataSourse = $0.posts
self.posts.dictionary = $0.users
self.user = $0.users[self.idProfile!]
}
}
var basicInfo = BasicInfoController()
var posts = NewsVC()
var dataSourse: [Model.Posts]?{
didSet{
var newPosts: [Model.Posts] = []
dataSourse?.forEach({ (post) in
newPosts.append(Model.Posts(body: post.body, authorId: post.authorId, id: post.id, user: user!, date: post.updated, tags: post.tags))
})
self.posts.dataSourse = newPosts
tableView.reloadData()
}
}
override func viewDidLoad()
{
super.viewDidLoad()
if idProfile == nil {
idProfile = DataStorage.standard.getUserId()
}
posts.viewController = self
posts.type = .NONE
posts.currChannel = channel
posts.onFullPost = {
[weak self] (type,post) in
let vc = self?.storyboard?.instantiateViewController(withIdentifier: fullPostControllerId) as! FullPostController
vc.type = type
vc.post = post
self?.navigationController!.pushViewController(vc, animated: true)
}
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
tableView.register(BasicInfoCell.self, forCellReuseIdentifier: basicInfoCellId)
tableView.register(InfoCell.self, forCellReuseIdentifier: infoCellId)
posts.viewController = self
@ -96,83 +139,105 @@ class ProfileViewController: UIViewController
tableView.reloadData()
}
var idProfile: Int?
var idProfile: Int? {
didSet {
channel = Model.Channels(people: [idProfile!], name: "", id: 0, tags: [])
}
}
override func viewWillAppear(_ animated: Bool) {
tabBarController?.tabBar.isHidden = false
if idProfile == nil {
idProfile = DataStorage.standard.getUserId()
}
user = Model.Channels.fullPeopleDict[idProfile!]
if let id = idProfile {
if let user = Model.idUser[id] {
self.user = user
} else {
Model.getUsers(for: [id]) { [weak self] (dic) in
self?.user = dic[id]
}
}
// requst for postsforuser was here. moved because of concrr
}
update()
setUpNavigarionBar()
}
func setUpNavigarionBar(){
navigationController?.navigationBar.prefersLargeTitles = true
//navigationItem.title = "\(user?.id ?? 0)"
// navigationController?.navigationBar.prefersLargeTitles = true
let uibarbutton = UIBarButtonItem(title: "More", style: .plain, target: self, action: #selector(showInformation))
navigationItem.rightBarButtonItems = [uibarbutton]
navigationItem.largeTitleDisplayMode = .always
}
let copyLink: UIAlertAction = {
let b = UIAlertAction(title: "Copy link", style: .default)
return b
}()
@objc func showInformation(){
// drafts
// saved
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let channelAction = UIAlertAction(title: "Add to a channel", style: .default){
[weak self] (_) in
let vc = self?.storyboard?.instantiateViewController(withIdentifier: simplifiedChannelsList) as! SimplifiedChannelsList
vc.user = self?.user!
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.moveIn
transition.subtype = CATransitionSubtype.fromTop
self?.navigationController?.view.layer.add(transition, forKey: nil)
self?.navigationController?.pushViewController(vc, animated: false)
}
let settingsAction = UIAlertAction(title: "Setting", style: .default)
{ [weak self] (_) in
let vc = self?.storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
self?.navigationController?.pushViewController(vc, animated: true)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
{
(_) in
DataStorage.standard.setIsLoggedIn(value: false, with: 0)
if idProfile == DataStorage.standard.getUserId() {
let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
{ [weak self] (_) in
if let logOut = self?.logOut {
logOut()
} else {
Model.logout() {
DataStorage.standard.setIsLoggedIn(value: false, with: 0)
(UIApplication.shared.delegate as! AppDelegate).relaunch()
}
}
}
let deleetAllSessionsAction = UIAlertAction(title: "Delete all sessions", style: .destructive)
{ [weak self] _ in
if let delete = self?.deleteAllSessions {
delete()
} else {
Model.deactivateAll() {
DataStorage.standard.setIsLoggedIn(value: false, with: 0)
(UIApplication.shared.delegate as! AppDelegate).relaunch()
}
}
}
let settingsAction = UIAlertAction(title: "Edit profile", style: .default)
{ [weak self] (_) in
if let settings = self?.onSettings{
settings()
} else {
let vc = self?.storyboard?.instantiateViewController(withIdentifier: "RegisterTableViewController") as! RegisterTableViewController
vc.delegate = self
vc.userActive = self?.user
self?.navigationController?.pushViewController(vc, animated: true)
}
}
optionMenu.addAction(settingsAction)
optionMenu.addAction(logoutAction)
optionMenu.addAction(deleetAllSessionsAction)
} else {
let channelAction = UIAlertAction(title: "Add to a channel", style: .default)
{
[weak self] (_) in
let vc = self?.storyboard?.instantiateViewController(withIdentifier: simplifiedChannelsList) as! SimplifiedChannelsList
vc.user = self?.user
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.moveIn
transition.subtype = CATransitionSubtype.fromTop
self?.navigationController?.view.layer.add(transition, forKey: nil)
self?.navigationController?.pushViewController(vc, animated: false)
}
optionMenu.addAction(channelAction)
}
optionMenu.addAction(channelAction)
optionMenu.addAction(settingsAction)
optionMenu.addAction(copyLink)
optionMenu.addAction(logoutAction)
optionMenu.addAction(cancelAction)
self.present(optionMenu, animated: true, completion: nil)
}
@ -202,6 +267,7 @@ class ProfileViewController: UIViewController
func changeToBasicInfo(){
tableView.delegate = basicInfo
tableView.dataSource = basicInfo
basicInfo.userInfo = self.user
tableView.reloadData()
}
}

View File

@ -1,59 +0,0 @@
/// RepeatingTimer mimics the API of DispatchSourceTimer but in a way that prevents
/// crashes that occur from calling resume multiple times on a timer that is
/// already resumed (noted by https://github.com/SiftScience/sift-ios/issues/52
import Foundation
class RepeatingTimer {
let timeInterval: TimeInterval
init(timeInterval: TimeInterval) {
self.timeInterval = timeInterval
}
private lazy var timer: DispatchSourceTimer = {
let t = DispatchSource.makeTimerSource()
t.schedule(deadline: .now() + self.timeInterval, repeating: self.timeInterval)
t.setEventHandler(handler: { [weak self] in
self?.eventHandler?()
})
return t
}()
var eventHandler: (() -> Void)?
private enum State {
case suspended
case resumed
}
private var state: State = .suspended
deinit {
timer.setEventHandler {}
timer.cancel()
/*
If the timer is suspended, calling cancel without resuming
triggers a crash. This is documented here https://forums.developer.apple.com/thread/15902
*/
resume()
eventHandler = nil
}
func resume() {
if state == .resumed {
return
}
state = .resumed
timer.resume()
}
func suspend() {
if state == .suspended {
return
}
state = .suspended
timer.suspend()
}
}

View File

@ -37,18 +37,17 @@ class DataStorage{
return UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
}
func setEmail(email: String) {
UserDefaults.standard.set(email, forKey: UserDefaultsKeys.email.rawValue)
}
func getEmail() -> String? {
return UserDefaults.standard.string(forKey: UserDefaultsKeys.email.rawValue)
}
/**
Function to determine is user logged in already or not
*/
var isLoggedIn: Bool = UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue) {
didSet{
if isLoggedIn && getUserId() != 0 {
(UIApplication.shared.delegate as? AppDelegate)?.tabCoordinator.start()
} else {
(UIApplication.shared.delegate as? AppDelegate)?.logInAgain()
}
}
}
var isLoggedIn: Bool = UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue)
}
/**
@ -57,4 +56,5 @@ class DataStorage{
enum UserDefaultsKeys: String{
case loggedIn
case id
case email
}

View File

@ -60,3 +60,50 @@ extension UIStoryboard {
return UIStoryboard.userEdit.instantiateViewController(withIdentifier: logInController) as! LogInViewController
}
}
extension String {
func getDate() -> String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"//this your string date format
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let date = dateFormatter.date(from: self)
dateFormatter.dateFormat = "MMM d, yyyy HH:mm" ///this is what you want to convert format
dateFormatter.timeZone = NSTimeZone.local
let timeStamp = dateFormatter.string(from: date!)
return timeStamp
}
}
extension UIViewController {
func showAlertOn(result: ResultR) {
let message: String
switch result {
case .impossibleContent:
message = "Impossible content"
case .exceededContent:
message = "The content exceeded"
case .longContent:
message = "The content is too long"
case .badAccess:
message = "Try reloading the page again"
case .alreadyRegistered:
message = "User is already registered"
case .tooMuchToAdd:
message = "Limit of channels exceeded"
case .success, .success1:
return
default:
message = "Something went wrong"
}
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}

View File

@ -0,0 +1,44 @@
//
// CompletionTree.swift
// GDproject
//
// Created by cstore on 01/05/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
struct CompletionTree: Codable {
var value: String?
var subtree: [String : CompletionTree]
static func getCompletion(tree: CompletionTree, word: String) -> [String] {
if word == "" {
return getValues(tree: tree)
}
let character = String(word.first!)
if tree.subtree[character] == nil {
return []
} else {
return getCompletion(tree: tree.subtree[character]!, word: String(word.dropFirst()))
}
}
static func getValues(tree: CompletionTree) -> [String]
{
var out = [String]()
if let treeVal = tree.value {
out.append(treeVal)
}
for (_, subtree) in tree.subtree {
out += getValues(tree: subtree)
}
return out
}
}

File diff suppressed because it is too large Load Diff

View File

@ -9,31 +9,6 @@
import Foundation
import UIKit
struct Post {
var dataArray: [Media]
var fromUser: User
var atDate: String
var comments: [Comment] = []
var hashtags: [String] = ["ФКН", "Подбельский", "НИУВШЭ", "Шершаков", "ПАД", "Интересное","Мемы","Забавное","Учеба","Наука"]
init(dataArray: [Media], from: User, date: String, comments: [Comment] = [])
{
self.dataArray = dataArray
fromUser = from
atDate = date
self.comments = comments
}
init(dataArray: [Media]) {
self.dataArray = dataArray
fromUser = User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна")
atDate = "23.03.19 в 23:33"
}
}
enum Media{
case text(String)
case image([UIImage])
@ -41,7 +16,6 @@ enum Media{
}
struct Comment {
var from: User
var atTime: String
var withData: String
}

View File

@ -1,41 +0,0 @@
//
// User.swift
// NewsFeed
//
// Created by cstore on 12/01/2019.
// Copyright © 2019 drHSE. All rights reserved.
//
import Foundation
import UIKit
struct User {
//var photo: UIImage? = #imageLiteral(resourceName: "image")
var login: String
var id: Int
var fullName: String
var initials: (surname: String, name: String, optional: String?) = ("Богомазова","Вероника","Львовна")
var placeOfWork: String?
var faculty: String?
let posts: [Post] = []
init(name: String, id: Int, fullName: String) {
self.login = name
self.id = id
self.fullName = fullName
}
init(surname: String, name: String, optional: String?, emailName: String, id: Int, place: String?, faculty: String?)
{
self.id = id
self.login = emailName
self.initials = (surname, name, optional)
self.fullName = "\(surname) \(name) \(optional ?? "")"
self.placeOfWork = place
if let f = faculty {
self.faculty = f
}
}
}

View File

@ -12,57 +12,28 @@ import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
var coordinator: LogInCoordinator!
var tabCoordinator: TabbarCoordinator!
var window: UIWindow?
var rootController: UINavigationController? {
return self.window!.rootViewController as? UINavigationController
}
func logInAgain(){
let root = UIStoryboard.navRoot()
window?.rootViewController = root
window?.makeKeyAndVisible()
coordinator = LogInCoordinator(navigationController: root, window: UIApplication.shared.keyWindow!)
coordinator!.start()
}
var appCoordinator: ApplicationCoordinator!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
coordinator = LogInCoordinator(navigationController: rootController!, window: window!)
tabCoordinator = TabbarCoordinator(window: window!)
// TODO:- determine what to do here: log in or tabbar
if DataStorage.standard.isLoggedIn {
tabCoordinator.start()
} else {
coordinator.start()
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
// window?.rootViewController = UINavigationController()
Model.getCompl { (complTree) in
Model.hashTagTree = complTree
}
appCoordinator = ApplicationCoordinator(window: window!)
appCoordinator.start()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// 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.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// 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.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// 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.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// 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.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
func relaunch(){
appCoordinator.start()
}
}

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "chat.pdf",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.