git.iko.soy/dashared/GDproject
on master help sign in
Channels: preview bag left. Added new view for adding hashtags. Some minor changes in api.
6850d76Darya Rednikina
GDproject.xcodeproj/project.pbxproj+4
@@ -9,6 +9,7 @@
9/* Begin PBXBuildFile section */
9/* Begin PBXBuildFile section */
10 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */; };
10 1210A0BB223940310080686D /* SimplifiedChannelsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */; };
11 121A8972226B1EAC005EE599 /* AnonimousChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */; };
11 121A8972226B1EAC005EE599 /* AnonimousChannelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */; };
12+ 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */; };
12 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
13 123E37A5221F1B3200F6E42A /* LogInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A4221F1B3200F6E42A /* LogInViewController.swift */; };
13 123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
14 123E37A7221F1DD700F6E42A /* MainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 123E37A6221F1DD700F6E42A /* MainController.swift */; };
14 124CC7032221C00C009DF531 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124CC7022221C00C009DF531 /* Model.swift */; };
15 124CC7032221C00C009DF531 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 124CC7022221C00C009DF531 /* Model.swift */; };
@@ -102,6 +103,7 @@
102/* Begin PBXFileReference section */
103/* Begin PBXFileReference section */
103 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplifiedChannelsList.swift; sourceTree = "<group>"; };
104 1210A0BA223940310080686D /* SimplifiedChannelsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplifiedChannelsList.swift; sourceTree = "<group>"; };
104 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnonimousChannelController.swift; sourceTree = "<group>"; };
105 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnonimousChannelController.swift; sourceTree = "<group>"; };
106+ 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaggsSelectionViewController.swift; sourceTree = "<group>"; };
105 123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
107 123E37A4221F1B3200F6E42A /* LogInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInViewController.swift; sourceTree = "<group>"; };
106 123E37A6221F1DD700F6E42A /* MainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
108 123E37A6221F1DD700F6E42A /* MainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainController.swift; sourceTree = "<group>"; };
107 124CC7022221C00C009DF531 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
109 124CC7022221C00C009DF531 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
@@ -311,6 +313,7 @@
311 isa = PBXGroup;
313 isa = PBXGroup;
312 children = (
314 children = (
313 1261BB92227B364C003898CF /* ChannelViewController.swift */,
315 1261BB92227B364C003898CF /* ChannelViewController.swift */,
316+ 1220FF93227C41270092C6BC /* TaggsSelectionViewController.swift */,
314 1261BB94227B3991003898CF /* AddToChannelVC.swift */,
317 1261BB94227B3991003898CF /* AddToChannelVC.swift */,
315 12D7D134221C42B700B35452 /* ChannelController.swift */,
318 12D7D134221C42B700B35452 /* ChannelController.swift */,
316 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */,
319 121A8971226B1EAC005EE599 /* AnonimousChannelController.swift */,
@@ -411,6 +414,7 @@
411 files = (
414 files = (
412 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */,
415 129320072279B5690035C7B3 /* MessagesCoordinator.swift in Sources */,
413 124CC7032221C00C009DF531 /* Model.swift in Sources */,
416 124CC7032221C00C009DF531 /* Model.swift in Sources */,
417+ 1220FF94227C41270092C6BC /* TaggsSelectionViewController.swift in Sources */,
414 12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */,
418 12F3D6B0224106F700A69214 /* TabbarController.swift in Sources */,
415 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
419 12E36DD522156559006FCDD7 /* MyStackView.swift in Sources */,
416 12D7D137221D78E800B35452 /* Channel.swift in Sources */,
420 12D7D137221D78E800B35452 /* Channel.swift in Sources */,
GDproject/Base.lproj/Main.storyboard+104−12
@@ -379,33 +379,35 @@
379 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
379 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
380 <subviews>
380 <subviews>
381 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aRT-Du-PVE">
381 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aRT-Du-PVE">
382− <rect key="frame" x="0.0" y="55" width="375" height="612"/>
382+ <rect key="frame" x="0.0" y="62" width="375" height="605"/>
383 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
383 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
384 </view>
384 </view>
385− <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="368-bf-QU6">
385+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bHv-9b-9uA">
386− <rect key="frame" x="0.0" y="20" width="375" height="35"/>
386+ <rect key="frame" x="16" y="32" width="343" height="30"/>
387− <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
388 <constraints>
387 <constraints>
389− <constraint firstAttribute="height" constant="35" id="5ER-su-0Yf"/>
388+ <constraint firstAttribute="height" constant="30" id="QPs-3f-AfA"/>
390 </constraints>
389 </constraints>
391− </view>
390+ <state key="normal" title="Edit hashtags"/>
391+ <connections>
392+ <action selector="chooseTags:" destination="uED-wX-77j" eventType="touchUpInside" id="jvf-w2-K2f"/>
393+ </connections>
394+ </button>
392 </subviews>
395 </subviews>
393 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
396 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
394 <constraints>
397 <constraints>
395 <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="aRT-Du-PVE" secondAttribute="trailing" id="2ee-e8-G7A"/>
398 <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="aRT-Du-PVE" secondAttribute="trailing" id="2ee-e8-G7A"/>
399+ <constraint firstItem="aRT-Du-PVE" firstAttribute="top" secondItem="bHv-9b-9uA" secondAttribute="bottom" id="6As-MU-bEh"/>
396− <constraint firstItem="368-bf-QU6" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="9Rl-wh-kZf"/>
400+ <constraint firstItem="bHv-9b-9uA" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" constant="16" id="OIV-hF-TBs"/>
401+ <constraint firstItem="bHv-9b-9uA" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" constant="12" id="REt-Jv-IfH"/>
397 <constraint firstItem="aRT-Du-PVE" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="UBy-Ch-zSL"/>
402 <constraint firstItem="aRT-Du-PVE" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="UBy-Ch-zSL"/>
398− <constraint firstItem="aRT-Du-PVE" firstAttribute="top" secondItem="368-bf-QU6" secondAttribute="bottom" id="WaE-kh-6w3"/>
403+ <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="bHv-9b-9uA" secondAttribute="trailing" constant="16" id="Ufp-mQ-Xeo"/>
399− <constraint firstItem="368-bf-QU6" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" id="aI9-JQ-7dq"/>
400− <constraint firstItem="368-bf-QU6" firstAttribute="trailing" secondItem="wxD-Ek-mgv" secondAttribute="trailing" id="haz-0r-Cud"/>
401 <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="aRT-Du-PVE" secondAttribute="bottom" id="x3f-eb-ACt"/>
404 <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="aRT-Du-PVE" secondAttribute="bottom" id="x3f-eb-ACt"/>
402 </constraints>
405 </constraints>
403 <viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
406 <viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
404 </view>
407 </view>
405 <connections>
408 <connections>
406 <outlet property="bottomTextViewConstraint" destination="x3f-eb-ACt" id="ktT-im-InH"/>
409 <outlet property="bottomTextViewConstraint" destination="x3f-eb-ACt" id="ktT-im-InH"/>
407− <outlet property="view1" destination="aRT-Du-PVE" id="m3d-kW-vqW"/>
410+ <outlet property="view1" destination="aRT-Du-PVE" id="DXD-HR-NcE"/>
408− <outlet property="viewForTags" destination="368-bf-QU6" id="M5s-RZ-Fq7"/>
409 </connections>
411 </connections>
410 </viewController>
412 </viewController>
411 <placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
413 <placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -430,6 +432,96 @@
430 </objects>
432 </objects>
431 <point key="canvasLocation" x="3444" y="129.98500749625188"/>
433 <point key="canvasLocation" x="3444" y="129.98500749625188"/>
432 </scene>
434 </scene>
435+ <!--Taggs Selection View Controller-->
436+ <scene sceneID="74G-Lc-cqT">
437+ <objects>
438+ <viewController storyboardIdentifier="TaggsSelectionViewController" id="rQl-ri-9O8" customClass="TaggsSelectionViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
439+ <view key="view" contentMode="scaleToFill" id="k3T-8B-NVf">
440+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
441+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
442+ <subviews>
443+ <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yeR-J3-ysT">
444+ <rect key="frame" x="16" y="131" width="343" height="142"/>
445+ <constraints>
446+ <constraint firstAttribute="height" constant="142" id="1By-sC-rMT"/>
447+ </constraints>
448+ </containerView>
449+ <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lEu-rZ-H6U">
450+ <rect key="frame" x="16" y="306" width="343" height="184"/>
451+ <constraints>
452+ <constraint firstAttribute="height" constant="184" id="F0W-3R-hCj"/>
453+ </constraints>
454+ </containerView>
455+ <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">
456+ <rect key="frame" x="16" y="28" width="73" height="21"/>
457+ <constraints>
458+ <constraint firstAttribute="height" constant="21" id="KZW-ld-K8d"/>
459+ </constraints>
460+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
461+ <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
462+ <nil key="highlightedColor"/>
463+ </label>
464+ <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">
465+ <rect key="frame" x="16" y="106" width="126" height="21"/>
466+ <constraints>
467+ <constraint firstAttribute="height" constant="21" id="ZJb-Aw-bLx"/>
468+ </constraints>
469+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
470+ <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
471+ <nil key="highlightedColor"/>
472+ </label>
473+ <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">
474+ <rect key="frame" x="16" y="281" width="101" height="21"/>
475+ <constraints>
476+ <constraint firstAttribute="height" constant="21" id="aT7-BK-i42"/>
477+ </constraints>
478+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
479+ <color key="textColor" red="0.43529411759999997" green="0.4431372549" blue="0.47450980390000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
480+ <nil key="highlightedColor"/>
481+ </label>
482+ <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">
483+ <rect key="frame" x="16" y="57" width="343" height="30"/>
484+ <constraints>
485+ <constraint firstAttribute="height" constant="30" id="dBr-rd-Cg8"/>
486+ </constraints>
487+ <nil key="textColor"/>
488+ <fontDescription key="fontDescription" type="system" pointSize="14"/>
489+ <textInputTraits key="textInputTraits"/>
490+ </textField>
491+ </subviews>
492+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
493+ <constraints>
494+ <constraint firstItem="hvS-Ix-A23" firstAttribute="top" secondItem="BgX-NT-7NG" secondAttribute="bottom" constant="19" id="17U-ae-Gxa"/>
495+ <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="yeR-J3-ysT" secondAttribute="trailing" constant="16" id="9gG-QD-LG4"/>
496+ <constraint firstItem="lxp-KC-Iua" firstAttribute="top" secondItem="yeR-J3-ysT" secondAttribute="bottom" constant="8" id="C3R-dM-Fzj"/>
497+ <constraint firstItem="uXC-Rm-Hek" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="E6w-kw-7Uo"/>
498+ <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="hvS-Ix-A23" secondAttribute="trailing" constant="233" id="GLM-Fj-UeZ"/>
499+ <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lxp-KC-Iua" secondAttribute="trailing" constant="258" id="Pbc-Ul-Bqf"/>
500+ <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="uXC-Rm-Hek" secondAttribute="trailing" constant="286" id="Uc1-pS-uKg"/>
501+ <constraint firstItem="lEu-rZ-H6U" firstAttribute="top" secondItem="lxp-KC-Iua" secondAttribute="bottom" constant="4" id="aew-vr-F7L"/>
502+ <constraint firstItem="uXC-Rm-Hek" firstAttribute="top" secondItem="Oc2-oW-bST" secondAttribute="top" constant="8" id="dGW-ps-wNH"/>
503+ <constraint firstItem="lxp-KC-Iua" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="gmr-z4-RMQ"/>
504+ <constraint firstItem="BgX-NT-7NG" firstAttribute="top" secondItem="uXC-Rm-Hek" secondAttribute="bottom" constant="8" id="jqp-Lv-waU"/>
505+ <constraint firstItem="yeR-J3-ysT" firstAttribute="top" secondItem="hvS-Ix-A23" secondAttribute="bottom" constant="4" id="nZ3-oH-0AF"/>
506+ <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="BgX-NT-7NG" secondAttribute="trailing" constant="16" id="pPk-Ih-GDO"/>
507+ <constraint firstItem="yeR-J3-ysT" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qBn-xg-Ioc"/>
508+ <constraint firstItem="lEu-rZ-H6U" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="qCJ-rc-qBq"/>
509+ <constraint firstItem="Oc2-oW-bST" firstAttribute="trailing" secondItem="lEu-rZ-H6U" secondAttribute="trailing" constant="16" id="vaR-Zr-5nI"/>
510+ <constraint firstItem="hvS-Ix-A23" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="vcb-xj-bM8"/>
511+ <constraint firstItem="BgX-NT-7NG" firstAttribute="leading" secondItem="Oc2-oW-bST" secondAttribute="leading" constant="16" id="xOL-J4-JIV"/>
512+ </constraints>
513+ <viewLayoutGuide key="safeArea" id="Oc2-oW-bST"/>
514+ </view>
515+ <connections>
516+ <outlet property="addTagsTextField" destination="BgX-NT-7NG" id="3vt-U9-NYI"/>
517+ <outlet property="searchContainerView" destination="yeR-J3-ysT" id="SzT-fM-A6H"/>
518+ <outlet property="testContainer" destination="lEu-rZ-H6U" id="DTe-9O-VAi"/>
519+ </connections>
520+ </viewController>
521+ <placeholder placeholderIdentifier="IBFirstResponder" id="eoH-1e-A6A" userLabel="First Responder" sceneMemberID="firstResponder"/>
522+ </objects>
523+ <point key="canvasLocation" x="4293.6000000000004" y="132.68365817091455"/>
524+ </scene>
433 <!--Messages View Controller-->
525 <!--Messages View Controller-->
434 <scene sceneID="WSW-fr-Vf8">
526 <scene sceneID="WSW-fr-Vf8">
435 <objects>
527 <objects>
GDproject/Constants.swift+2
@@ -59,5 +59,7 @@ let channelViewControllerId = "ChannelViewController"
59
59
60let addToChannelVCId = "AddToChannelVC"
60let addToChannelVCId = "AddToChannelVC"
61
61
62+let taggsSelectionViewController = "TaggsSelectionViewController"
63+
62let blueSystemColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)
64let blueSystemColor = UIColor(red: 0, green: 137/255, blue: 249/255, alpha: 0.5)
63
65
GDproject/Controller/ News and channels/AddToChannelVC.swift+41−26
@@ -15,35 +15,42 @@ enum DataSourse{
15class AddToChannelVC: UITableViewController {
15class AddToChannelVC: UITableViewController {
16
16
17 var channel: Model.Channels?
17 var channel: Model.Channels?
18− var dataSourse: DataSourse = .people
19 weak var update: UpdatableChannel?
18 weak var update: UpdatableChannel?
20
19
21 // data sources for people and hashtags
20 // data sources for people and hashtags
22 var dataSourcePeople: [Model.Users] = Model.Channels.fullPeople
21 var dataSourcePeople: [Model.Users] = Model.Channels.fullPeople
23− var fullTags: [String] = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
24−
25
22
26 var reloadtable: Bool = false {
23 var reloadtable: Bool = false {
27 didSet{
24 didSet{
28 tableView.reloadData()
25 tableView.reloadData()
29 }
26 }
30 }
27 }
28+
29+ var filteredDataSource = [Model.Users]()
30+
31+ func filterContentForSearchText(_ searchText: String, scope: String = "All")
32+ {
33+ filteredDataSource = dataSourcePeople.filter { $0.fullName().lowercased().contains(searchText.lowercased()) }
34+ tableView.reloadData()
35+ }
31
36
32 let searchC = UISearchController(searchResultsController: nil)
37 let searchC = UISearchController(searchResultsController: nil)
33
38
34 override func viewDidLoad() {
39 override func viewDidLoad() {
35 super.viewDidLoad()
40 super.viewDidLoad()
36
41
42+ navigationItem.title = "People"
37 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
43 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
38 self.navigationItem.searchController = searchC
44 self.navigationItem.searchController = searchC
39 navigationItem.largeTitleDisplayMode = .never
45 navigationItem.largeTitleDisplayMode = .never
40 self.navigationItem.hidesSearchBarWhenScrolling = false
46 self.navigationItem.hidesSearchBarWhenScrolling = false
41−
47+ definesPresentationContext = true
48+ searchC.searchResultsUpdater = self
49+ searchC.obscuresBackgroundDuringPresentation = false
42 }
50 }
43
51
44 override func viewWillDisappear(_ animated: Bool) {
52 override func viewWillDisappear(_ animated: Bool) {
45 super.viewWillDisappear(animated)
53 super.viewWillDisappear(animated)
46−
47 update?.updateChannel(with: channel!)
54 update?.updateChannel(with: channel!)
48 }
55 }
49 // MARK: - Table view data source
56 // MARK: - Table view data source
@@ -52,12 +59,19 @@ class AddToChannelVC: UITableViewController {
52 return 1
59 return 1
53 }
60 }
54
61
62+ var isFiltering: Bool {
63+ return searchC.isActive && !searchBarIsEmpty()
64+ }
65+
66+ func searchBarIsEmpty() -> Bool {
67+ return searchC.searchBar.text?.isEmpty ?? true
68+ }
69+
55 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
70 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
56− switch dataSourse {
71+ if isFiltering {
57− case .people:
72+ return filteredDataSource.count
73+ } else {
58 return dataSourcePeople.count
74 return dataSourcePeople.count
59− default:
60− return fullTags.count
61 }
75 }
62 }
76 }
63
77
@@ -65,17 +79,16 @@ class AddToChannelVC: UITableViewController {
65 {
79 {
66 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
80 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
67
81
68− switch dataSourse {
82+ if isFiltering{
69− case .people:
70− cell.textLabel?.text = dataSourcePeople[indexPath.row].fullName()
83+ cell.textLabel?.text = filteredDataSource[indexPath.row].fullName()
71− if channel!.people.contains(dataSourcePeople[indexPath.row].id) {
84+ if channel!.people.contains(filteredDataSource[indexPath.row].id) {
72 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
85 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
73 } else {
86 } else {
74 cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
87 cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
75 }
88 }
76− default:
89+ } else {
77− cell.textLabel?.text = "# \(fullTags[indexPath.row])"
90+ cell.textLabel?.text = dataSourcePeople[indexPath.row].fullName()
78− if channel!.tags.contains(fullTags[indexPath.row]) {
91+ if channel!.people.contains(dataSourcePeople[indexPath.row].id) {
79 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
92 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
80 } else {
93 } else {
81 cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
94 cell.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
@@ -89,29 +102,31 @@ class AddToChannelVC: UITableViewController {
89
102
90 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
103 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
91 if let cell = tableView.cellForRow(at: indexPath) {
104 if let cell = tableView.cellForRow(at: indexPath) {
92− switch dataSourse {
105+ if isFiltering{
93− case .people:
94 if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
106 if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
95− let filtered = channel!.people.filter{ $0 != dataSourcePeople[indexPath.row].id }
107+ let filtered = channel!.people.filter{ $0 != filteredDataSource[indexPath.row].id }
96 channel?.people = filtered
108 channel?.people = filtered
97 cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
109 cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
98 } else {
110 } else {
99− channel?.people.append(dataSourcePeople[indexPath.row].id)
111+ channel?.people.append(filteredDataSource[indexPath.row].id)
100 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
112 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
101 }
113 }
102− default: //tags
114+ } else {
103 if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
115 if cell.backgroundColor == #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1) {
104− let filtered = channel!.tags.filter{
116+ let filtered = channel!.people.filter{ $0 != dataSourcePeople[indexPath.row].id }
105− !fullTags[indexPath.row].contains($0)
106− }
107− channel?.tags = filtered
117+ channel?.people = filtered
108 cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
118 cell.backgroundColor = #colorLiteral(red: 0.9999960065, green: 1, blue: 1, alpha: 1)
109 } else {
119 } else {
110− channel?.tags.append(fullTags[indexPath.row])
120+ channel?.people.append(dataSourcePeople[indexPath.row].id)
111 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
121 cell.backgroundColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
112 }
122 }
113 }
123 }
114 }
124 }
115 }
125 }
126+}
116
127
128+extension AddToChannelVC : UISearchResultsUpdating {
129+ func updateSearchResults(for searchController: UISearchController) {
130+ filterContentForSearchText(searchController.searchBar.text!)
131+ }
117}
132}
GDproject/Controller/ News and channels/ChannelViewController.swift+16−10
@@ -16,7 +16,15 @@ protocol UpdatableChannel: class{
16 func updateChannel(with channel: Model.Channels)
16 func updateChannel(with channel: Model.Channels)
17}
17}
18
18
19−class ChannelViewController: UITableViewController, UpdatableName, UpdatableChannel {
19+class ChannelViewController: UITableViewController, UpdatableName, UpdatableChannel, TagsReceiver
20+{
21+ var onChoosingHashTags: (([String]?)->())?
22+
23+ var onChoosingPeople: ((Model.Channels?)->())?
24+
25+ func receiveTags(tags: [String]) {
26+ self.channel?.tags = tags
27+ }
20
28
21 func updateName(with name: String){
29 func updateName(with name: String){
22 channel?.name = name
30 channel?.name = name
@@ -34,7 +42,7 @@ class ChannelViewController: UITableViewController, UpdatableName, UpdatableChan
34 override func viewDidLoad()
42 override func viewDidLoad()
35 {
43 {
36 super.viewDidLoad()
44 super.viewDidLoad()
37−
45+ tableView.keyboardDismissMode = .onDrag
38 navigationItem.rightBarButtonItems = [ UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(showPreview)), self.editButtonItem]
46 navigationItem.rightBarButtonItems = [ UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(showPreview)), self.editButtonItem]
39 navigationItem.largeTitleDisplayMode = .never
47 navigationItem.largeTitleDisplayMode = .never
40 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
48 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
@@ -160,15 +168,13 @@ class ChannelViewController: UITableViewController, UpdatableName, UpdatableChan
160
168
161 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
169 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
162 {
170 {
163− if indexPath.row == 0 && indexPath.section != 0
171+ if indexPath.row == 0 && indexPath.section == 1
164 {
172 {
165− let vc = storyboard?.instantiateViewController(withIdentifier: addToChannelVCId) as! AddToChannelVC
173+ onChoosingPeople?(channel)
166−
174+ }
175+
167− vc.dataSourse = indexPath.section == 1 ? .people : .tags
176+ if indexPath.row == 0 && indexPath.section == 2 {
168− vc.channel = channel
177+ onChoosingHashTags?(channel?.tags)
169− vc.update = self
170−
171− navigationController?.pushViewController(vc, animated: true)
172 }
178 }
173 }
179 }
174}
180}
GDproject/Controller/ News and channels/NewPostViewController.swift+22−4
@@ -10,20 +10,38 @@ import UIKit
10import Cartography
10import Cartography
11import Marklight
11import Marklight
12import TinyConstraints
12import TinyConstraints
13+import TaggerKit
13// import WSTagsField
14// import WSTagsField
14
15
15−class NewPostViewController: UIViewController, UITextViewDelegate {
16+class NewPostViewController: UIViewController, UITextViewDelegate, TagsReceiver
17+{
18+ func receiveTags(tags: [String]) {
19+ currentTags = tags
20+ }
16
21
17 @IBOutlet weak var view1: UIView!
22 @IBOutlet weak var view1: UIView!
18
23
19− @IBOutlet weak var viewForTags: UIView!
24+ var currentTags: [String] = []
25+
26+ // We want the whole experience, let's create two TKCollectionViews
27+ let productTags = TKCollectionView()
28+
29+ @IBAction func chooseTags(_ sender: UIButton) {
30+ let vc = storyboard?.instantiateViewController(withIdentifier: taggsSelectionViewController) as! TaggsSelectionViewController
31+
32+ NewPostViewController.draft = textView.text
33+ vc.receiver = self
34+ vc.currentTags = currentTags
35+
36+ navigationController?.pushViewController(vc, animated: true)
37+ }
20
38
21 // fileprivate let tagsField = WSTagsField()
39 // fileprivate let tagsField = WSTagsField()
22 // Keep strong instance of the `NSTextStorage` subclass
40 // Keep strong instance of the `NSTextStorage` subclass
23 let textStorage = MarklightTextStorage()
41 let textStorage = MarklightTextStorage()
24
42
25 static var draft: String = ""
43 static var draft: String = ""
26− static var hashTagsDraft: [String] = []
44+ static var hashTagsDraft: [String] = ["tt"]
27
45
28 var textView: UITextView!
46 var textView: UITextView!
29
47
@@ -213,7 +231,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
213 var indexOfPost = 0
231 var indexOfPost = 0
214 // MARK:- new post
232 // MARK:- new post
215 @objc func newPost(){
233 @objc func newPost(){
216− Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: /*tagsField.tags.map { $0.text }*/ [])
234+ Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: currentTags)
217 // adding row to uiTableView after adding new post
235 // adding row to uiTableView after adding new post
218 // myProtocol?.addPost(post: p)
236 // myProtocol?.addPost(post: p)
219 moveBackToParentVC?()
237 moveBackToParentVC?()
GDproject/Controller/ News and channels/TaggsSelectionViewController.swiftnew file+106
@@ -0,0 +1,106 @@
1+//
2+// TaggsSelectionViewController.swift
3+// GDproject
4+//
5+// Created by cstore on 03/05/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+import TaggerKit
11+
12+protocol TagsReceiver: class {
13+ func receiveTags(tags: [String])
14+}
15+
16+class TaggsSelectionViewController: UIViewController {
17+
18+ @IBOutlet weak var addTagsTextField: TKTextField!
19+
20+ @IBOutlet weak var searchContainerView: UIView!
21+
22+ @IBOutlet weak var testContainer: UIView!
23+
24+ // We want the whole experience, let's create two TKCollectionViews
25+ let productTags = TKCollectionView()
26+ let allTags = TKCollectionView()
27+
28+ var currentTags: [String]?
29+ weak var receiver: TagsReceiver?
30+
31+ // MARK: - Lifecycle Methods
32+ override func viewDidLoad() {
33+ super.viewDidLoad()
34+
35+ navigationItem.title = "Hashtags"
36+ addTagsTextField.delegate = self
37+ // Customisation example
38+ // testCollection.customFont = UIFont.boldSystemFont(ofSize: 14) // Custom font
39+ // testCollection.customCornerRadius = 14.0 // Corner radius of tags
40+ // testCollection.customSpacing = 20.0 // Spacing between cells
41+ // testCollection.customBackgroundColor = UIColor.red // Background of cells
42+
43+
44+ // These are the tags already added by the user, give an aray of strings to the collection
45+ if let tags = currentTags {
46+ productTags.tags = tags
47+ }
48+ // These are intended to be all the tags the user has added in the app, which are going to be filtered
49+ allTags.tags = CompletionTree.getCompletion(tree: Model.hashTagTree!, word: "")
50+
51+ /*
52+ We set this collection's action to .removeTag,
53+ becasue these are supposed to be the tags the user has already added
54+ */
55+ productTags.action = .removeTag
56+
57+
58+ // Set the current controller as the delegate of both collections
59+ productTags.delegate = self
60+ allTags.delegate = self
61+
62+ // "testCollection" takes the tags sent by "searchCollection"
63+ allTags.receiver = productTags
64+
65+ // The tags in "searchCollection" are going to be added, so we set the action to addTag
66+ allTags.action = .addTag
67+
68+
69+ // Set the sender and receiver of the TextField
70+ addTagsTextField.sender = allTags
71+ addTagsTextField.receiver = productTags
72+
73+ add(productTags, toView: testContainer)
74+ add(allTags, toView: searchContainerView)
75+ }
76+
77+ override func viewWillDisappear(_ animated: Bool) {
78+ super.viewWillDisappear(animated)
79+ if let receiver = receiver{
80+ receiver.receiveTags(tags: productTags.tags)
81+ }
82+ }
83+
84+ /*
85+ These methods come from UIViewController now conforming to TKCollectionViewDelegate,
86+ You use these to do whatever you want when a tag is added or removed (e.g. save to file, etc)
87+ */
88+ override func tagIsBeingAdded(name: String?) {
89+ // Example: save testCollection.tags to UserDefault
90+ print("added \(name!)")
91+ }
92+
93+ override func tagIsBeingRemoved(name: String?) {
94+ print("removed \(name!)")
95+ }
96+}
97+
98+// textField deletage to close keyboard on return
99+extension TaggsSelectionViewController: UITextFieldDelegate
100+{
101+ func textFieldShouldReturn(_ textField: UITextField) -> Bool
102+ {
103+ self.view.endEditing(true)
104+ return false
105+ }
106+}
GDproject/Controller/Coordinators/ChannelsCoordinator.swift+20
@@ -55,6 +55,26 @@ class ChannelsCoordinator: BaseCoordinator{
55 let vc = self.presentNewsController(with: ch, previewMode: true)
55 let vc = self.presentNewsController(with: ch, previewMode: true)
56 mainContentVC?.navigationController?.pushViewController(vc, animated: true)
56 mainContentVC?.navigationController?.pushViewController(vc, animated: true)
57 }
57 }
58+
59+ // to go for choosing hashtags
60+ mainContentVC.onChoosingHashTags = { [weak mainContentVC, unowned self] ch in
61+ let vc = self.storyboard.instantiateViewController(withIdentifier: taggsSelectionViewController) as! TaggsSelectionViewController
62+
63+ vc.currentTags = ch
64+ vc.receiver = mainContentVC
65+
66+ self.navigationController?.pushViewController(vc, animated: true)
67+ }
68+
69+ mainContentVC.onChoosingPeople = { [weak mainContentVC, unowned self] channel in
70+ let vc = self.storyboard.instantiateViewController(withIdentifier: addToChannelVCId) as! AddToChannelVC
71+
72+ vc.channel = channel
73+ vc.update = mainContentVC
74+
75+ self.navigationController?.pushViewController(vc, animated: true)
76+ }
77+
58 mainContentVC.channel = channel
78 mainContentVC.channel = channel
59 return mainContentVC
79 return mainContentVC
60 }
80 }
GDproject/Simple model/Model.swift+30−9
@@ -41,6 +41,15 @@ class Model{
41 static let channelsGetAnonURL = URL(string: "\(baseUrl)/channels/getAnonymous")!
41 static let channelsGetAnonURL = URL(string: "\(baseUrl)/channels/getAnonymous")!
42 static let complexURL = URL(string: "\(baseUrl)/complex")!
42 static let complexURL = URL(string: "\(baseUrl)/complex")!
43 static let hashTagTreeURL = URL(string: "\(baseUrl)/tagCompletions")!
43 static let hashTagTreeURL = URL(string: "\(baseUrl)/tagCompletions")!
44+ static let createGroupChatURL = URL(string: "\(baseUrl)/chats/createGroupChat")!
45+ static let chatsGetAllURL = URL(string: "\(baseUrl)/chats/getAll")!
46+ static let getGroupChatURL = URL(string: "\(baseUrl)/chats/getGroupChat")!
47+ static let leaveGroupChatURL = URL(string: "\(baseUrl)/chats/leaveGroupChat")!
48+ static let updateGroupChatURL = URL(string: "\(baseUrl)/chats/updateGroupChat")!
49+ static let messagesGetGroupChatURL = URL(string: "\(baseUrl)/messages/get/groupChat")! //r
50+ static let messagesSendURL = URL(string: "\(baseUrl)/messages/send")!
51+ static let messagesUserChatURL = URL(string: "\(baseUrl)/messages/userChat")!
52+
44
53
45 struct QueryPosts: Codable {
54 struct QueryPosts: Codable {
46 var users: [Int: Users]
55 var users: [Int: Users]
@@ -212,15 +221,25 @@ class Model{
212 }
221 }
213 }
222 }
214
223
215− struct PostsLastRequest<T: Codable>: Codable {
224+ struct GeneralRequest<T: Codable>: Codable
225+ {
226+ var direction: String
216 var limit: Int
227 var limit: Int
217 var exclusiveFrom: Int?
228 var exclusiveFrom: Int?
218 var request: T
229 var request: T
219
230
231+ init(direction: String = "backward", limit: Int, exclusiveFrom: Int?, request: T) {
232+ self.direction = direction
233+ self.limit = limit
234+ self.exclusiveFrom = exclusiveFrom
235+ self.request = request
236+ }
237+
220 enum CodingKeys: String, CodingKey {
238 enum CodingKeys: String, CodingKey {
221 case limit
239 case limit
222 case exclusiveFrom
240 case exclusiveFrom
223 case request
241 case request
242+ case direction
224 }
243 }
225
244
226 func encode(to encoder: Encoder) throws {
245 func encode(to encoder: Encoder) throws {
@@ -228,12 +247,13 @@ class Model{
228 try container.encode(limit, forKey: .limit)
247 try container.encode(limit, forKey: .limit)
229 try container.encode(exclusiveFrom, forKey: .exclusiveFrom)
248 try container.encode(exclusiveFrom, forKey: .exclusiveFrom)
230 try container.encode(request, forKey: .request)
249 try container.encode(request, forKey: .request)
250+ try container.encode(direction, forKey: .direction)
231 }
251 }
232 }
252 }
233
253
234 static func getLast(on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
254 static func getLast(on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
235 {
255 {
236− let postRequest = PostsLastRequest<[Int]>(limit: limit, exclusiveFrom: pointInTime, request: [])
256+ let postRequest = GeneralRequest<[Int]>(limit: limit, exclusiveFrom: pointInTime, request: [])
237
257
238 var request = URLRequest(url: postsLastURL)
258 var request = URLRequest(url: postsLastURL)
239 request.httpBody = try? JSONEncoder().encode(postRequest)
259 request.httpBody = try? JSONEncoder().encode(postRequest)
@@ -275,14 +295,15 @@ class Model{
275 }
295 }
276 }
296 }
277
297
298+// static func requestForPosts(limit: Int = 10, ){
299+//
300+// }
278
301
279− static func getPostsForUser(with id: Int, completion: @escaping (([Posts])->())){
302+ static func getPostsForUser(for limit: Int = 10, from pointInTime: Int? = nil, with id: Int, completion: @escaping (([Posts])->()))
280− let json = [
303+ {
281− "request" : id,
304+ let postsRequest = GeneralRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: id)
282− "limit": 10
283− ]
284
305
285− let jsonData = try? JSONSerialization.data(withJSONObject: json)
306+ let jsonData = try? JSONEncoder().encode(postsRequest)
286
307
287 var request = URLRequest(url: postsForUserURL)
308 var request = URLRequest(url: postsForUserURL)
288 request.httpMethod = "POST"
309 request.httpMethod = "POST"
@@ -338,7 +359,7 @@ class Model{
338 // get channel (with id): in responce -- PostQuery
359 // get channel (with id): in responce -- PostQuery
339 static func getChannel(with channelId: Int, on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
360 static func getChannel(with channelId: Int, on limit: Int = 10, from pointInTime: Int? = nil, completion: @escaping (((users:[Int: Users], posts:[Posts]))->()))
340 {
361 {
341− let postRequest = PostsLastRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: channelId)
362+ let postRequest = GeneralRequest<Int>(limit: limit, exclusiveFrom: pointInTime, request: channelId)
342 let jsonData = try? JSONEncoder().encode(postRequest)
363 let jsonData = try? JSONEncoder().encode(postRequest)
343
364
344 var request = URLRequest(url: channelsGetURL)
365 var request = URLRequest(url: channelsGetURL)