mirror of
https://github.com/dashared/GDproject.git
synced 2024-11-29 02:54:30 +03:00
commit
1aeab21fec
4
Cartfile
4
Cartfile
@ -2,4 +2,6 @@ github "robb/Cartography"
|
||||
github "ivanbruel/MarkdownKit"
|
||||
github "roberthein/TinyConstraints"
|
||||
github "macteo/Marklight"
|
||||
github "ElaWorkshop/TagListView"
|
||||
github "ElaWorkshop/TagListView"
|
||||
github "Alamofire/Alamofire" "5.0.0-beta.2"
|
||||
github "whitesmith/WSTagsField"
|
||||
|
@ -7,14 +7,22 @@
|
||||
objects = {
|
||||
|
||||
/* 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, ); }; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@ -55,9 +63,11 @@
|
||||
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 */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
@ -66,14 +76,20 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* 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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -109,9 +125,11 @@
|
||||
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 */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -140,9 +158,20 @@
|
||||
path = "Coordinator tab bar?";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1291BE3722218DC4009D3F23 /* Log In */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
|
||||
1291BE3522218DBF009D3F23 /* LogInCoordinator.swift */,
|
||||
);
|
||||
path = "Log In";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
12E36D8F221424EA006FCDD7 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
123AD0E2223C1C3900326173 /* WSTagsField.framework */,
|
||||
124CC7042221C2BA009DF531 /* Alamofire.framework */,
|
||||
12E36DD622159493006FCDD7 /* TagListView.framework */,
|
||||
12E36DB422143D54006FCDD7 /* TinyConstraints.framework */,
|
||||
12E36DB222143D4E006FCDD7 /* Marklight.framework */,
|
||||
@ -182,6 +211,7 @@
|
||||
12E36DBA2214401B006FCDD7 /* Simple model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
124CC7022221C00C009DF531 /* Model.swift */,
|
||||
12E36DB62214400A006FCDD7 /* Post.swift */,
|
||||
12D7D136221D78E800B35452 /* Channel.swift */,
|
||||
12E36DB822144016006FCDD7 /* User.swift */,
|
||||
@ -202,8 +232,9 @@
|
||||
12E36DCF22145923006FCDD7 /* Controller */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1253867C2223DC9F00CC5EA7 /* RepeatingTimer.swift */,
|
||||
1291BE32222154C3009D3F23 /* Coordinator tab bar? */,
|
||||
123E37A4221F1B3200F6E42A /* LogInViewController.swift */,
|
||||
1291BE3722218DC4009D3F23 /* Log In */,
|
||||
1288B5CC221F0EFE002BE6B1 /* Profile */,
|
||||
12E36DD322156519006FCDD7 /* News and channels */,
|
||||
);
|
||||
@ -215,6 +246,7 @@
|
||||
children = (
|
||||
12D7D134221C42B700B35452 /* ChannelController.swift */,
|
||||
12D7D132221C321600B35452 /* ChannelListController.swift */,
|
||||
1210A0BA223940310080686D /* SimplifiedChannelsList.swift */,
|
||||
12E36DC922144635006FCDD7 /* NewPostViewController.swift */,
|
||||
12E36DD022148122006FCDD7 /* FullPostController.swift */,
|
||||
12E36D9D221424EA006FCDD7 /* NewsController.swift */,
|
||||
@ -304,9 +336,12 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
124CC7032221C00C009DF531 /* Model.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 */,
|
||||
@ -321,6 +356,7 @@
|
||||
12E36DD122148122006FCDD7 /* FullPostController.swift in Sources */,
|
||||
1288B5CE221F1158002BE6B1 /* DataStorage.swift in Sources */,
|
||||
125BD57D22171D2A008A3575 /* ProfileViewController.swift in Sources */,
|
||||
1253867D2223DC9F00CC5EA7 /* RepeatingTimer.swift in Sources */,
|
||||
12DB7FDB2218590C0096878E /* InfoCell.swift in Sources */,
|
||||
12DB7FD922181E660096878E /* BasicInfoCell.swift in Sources */,
|
||||
12D7D135221C42B700B35452 /* ChannelController.swift in Sources */,
|
||||
|
106
GDproject.xcodeproj/xcshareddata/xcschemes/GDproject.xcscheme
Normal file
106
GDproject.xcodeproj/xcshareddata/xcschemes/GDproject.xcscheme
Normal file
@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1010"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "12E36D97221424EA006FCDD7"
|
||||
BuildableName = "GDproject.app"
|
||||
BlueprintName = "GDproject"
|
||||
ReferencedContainer = "container:GDproject.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "12E36D97221424EA006FCDD7"
|
||||
BuildableName = "GDproject.app"
|
||||
BlueprintName = "GDproject"
|
||||
ReferencedContainer = "container:GDproject.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "12E36D97221424EA006FCDD7"
|
||||
BuildableName = "GDproject.app"
|
||||
BlueprintName = "GDproject"
|
||||
ReferencedContainer = "container:GDproject.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
<AdditionalOption
|
||||
key = "MallocStackLogging"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "PrefersMallocStackLoggingLite"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
<AdditionalOption
|
||||
key = "MallocScribble"
|
||||
value = ""
|
||||
isEnabled = "YES">
|
||||
</AdditionalOption>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "12E36D97221424EA006FCDD7"
|
||||
BuildableName = "GDproject.app"
|
||||
BlueprintName = "GDproject"
|
||||
ReferencedContainer = "container:GDproject.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
@ -74,8 +74,8 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yir-N6-Q6f">
|
||||
<rect key="frame" x="297" y="0.0" width="46" height="30"/>
|
||||
<state key="normal" title="Button"/>
|
||||
<rect key="frame" x="246" y="0.0" width="97" height="30"/>
|
||||
<state key="normal" title="New message"/>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
@ -214,6 +214,50 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2803" y="1756"/>
|
||||
</scene>
|
||||
<!--Simplified Channels List-->
|
||||
<scene sceneID="gAa-jy-vpG">
|
||||
<objects>
|
||||
<tableViewController storyboardIdentifier="SimplifiedChannelsList" id="pgD-Fz-bkD" customClass="SimplifiedChannelsList" 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="Onz-Ne-JgO">
|
||||
<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" restorationIdentifier="cell" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell1" textLabel="mZB-IA-VFq" detailTextLabel="6A8-yj-Eqe" style="IBUITableViewCellStyleSubtitle" id="6dT-km-gZC">
|
||||
<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="6dT-km-gZC" id="h7U-va-4PX">
|
||||
<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="mZB-IA-VFq">
|
||||
<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="6A8-yj-Eqe">
|
||||
<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="pgD-Fz-bkD" id="V4y-ql-GOS"/>
|
||||
<outlet property="delegate" destination="pgD-Fz-bkD" id="Avz-4G-8j6"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="731-nV-bC3" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4372" y="-598"/>
|
||||
</scene>
|
||||
<!--Channel List Controller-->
|
||||
<scene sceneID="4eb-Jz-gcx">
|
||||
<objects>
|
||||
@ -320,23 +364,34 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sSz-uJ-A7n">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aRT-Du-PVE">
|
||||
<rect key="frame" x="0.0" y="55" width="375" height="612"/>
|
||||
<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"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="35" id="5ER-su-0Yf"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="sSz-uJ-A7n" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="2J7-Bi-PzG"/>
|
||||
<constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="sSz-uJ-A7n" secondAttribute="trailing" id="HrU-bs-qsE"/>
|
||||
<constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="sSz-uJ-A7n" secondAttribute="bottom" id="oZ7-xQ-9Cb"/>
|
||||
<constraint firstItem="sSz-uJ-A7n" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" id="zuN-mZ-hgU"/>
|
||||
<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="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="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="oZ7-xQ-9Cb" id="6In-71-0TX"/>
|
||||
<outlet property="view1" destination="sSz-uJ-A7n" id="5nX-oT-kUi"/>
|
||||
<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"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@ -387,16 +442,22 @@
|
||||
</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>
|
||||
</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"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="LOR-Yw-0FU"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="indicatorView" destination="K3b-gv-JPp" id="mSR-QU-VZQ"/>
|
||||
<outlet property="mailTextField" destination="mFP-WG-jY5" id="7SN-qe-DDm"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
@ -408,7 +469,7 @@
|
||||
<scene sceneID="RSd-UJ-34B">
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="navChannels" automaticallyAdjustsScrollViewInsets="NO" id="NuV-ZG-ld2" sceneMemberID="viewController">
|
||||
<tabBarItem key="tabBarItem" title="Posts" id="dH2-sL-YsR"/>
|
||||
<tabBarItem key="tabBarItem" title="Posts" image="5" selectedImage="5" id="dH2-sL-YsR"/>
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="6qB-3A-tuL">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="96"/>
|
||||
@ -437,7 +498,7 @@
|
||||
<outlet property="delegate" destination="Nqc-TI-ueQ" id="kTM-Be-8qb"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" id="b8E-6f-hLM"/>
|
||||
<navigationItem key="navigationItem" largeTitleDisplayMode="always" id="b8E-6f-hLM"/>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="c9d-Kh-itI" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
@ -447,7 +508,7 @@
|
||||
<scene sceneID="dJj-Hp-Wa9">
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="navPosts" automaticallyAdjustsScrollViewInsets="NO" id="tae-5q-wvT" sceneMemberID="viewController">
|
||||
<tabBarItem key="tabBarItem" title="Profile" id="lYy-LQ-AcR"/>
|
||||
<tabBarItem key="tabBarItem" title="Profile" image="1" selectedImage="1" id="lYy-LQ-AcR"/>
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="q3a-ph-c8V">
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="96"/>
|
||||
@ -465,7 +526,7 @@
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="r0M-xH-UwU">
|
||||
<objects>
|
||||
<navigationController id="609-2j-gc9" sceneMemberID="viewController">
|
||||
<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"/>
|
||||
@ -495,4 +556,8 @@
|
||||
<point key="canvasLocation" x="-466" y="641"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="1" width="30" height="30"/>
|
||||
<image name="5" width="30" height="30"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
@ -41,3 +41,8 @@ let newsController = "NewsController"
|
||||
|
||||
/// constant for switching to view controller for log in app
|
||||
let logInController = "LogInController"
|
||||
|
||||
|
||||
let profileViewController = "ProfileViewController"
|
||||
|
||||
let simplifiedChannelsList = "SimplifiedChannelsList"
|
||||
|
@ -9,7 +9,12 @@
|
||||
import UIKit
|
||||
|
||||
protocol DataDelegate {
|
||||
func passData(for row: Int, channel: Channel)
|
||||
func passData(for row: Int, channel: Model.Channels)
|
||||
}
|
||||
|
||||
enum ActiveTable {
|
||||
case tags
|
||||
case people
|
||||
}
|
||||
|
||||
class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, UISearchBarDelegate
|
||||
@ -17,14 +22,16 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
|
||||
var index: Int?
|
||||
var channel: Channel?
|
||||
var channel: Model.Channels?
|
||||
var myProtocol: DataDelegate?
|
||||
|
||||
var dataSource: [String] = []
|
||||
var fullTags: [String] = Array(Model.Channels.fullTags)
|
||||
|
||||
var fullPeople: [String] = ["Other Ann", "Other Ilya", "Other Kostya", "Pasha", "Valera"]
|
||||
var dataSourcePeople: [Model.Users] = []
|
||||
|
||||
var fullTags: [String] = ["# happy", "# sad", "# meme", "# shershakov", "# pupsik"]
|
||||
var dataSourceTags: [String] = []
|
||||
|
||||
var activeDataSource: ActiveTable = .people
|
||||
|
||||
@IBOutlet weak var viewww: UIView!
|
||||
|
||||
@ -32,23 +39,58 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
dataSourceTags = channel!.tags
|
||||
setUpController()
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
var reloadtable: Bool = false {
|
||||
didSet{
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
Model.getUsers(for: channel!.people) { [weak self] (people) in
|
||||
self?.dataSourcePeople = Array(people.values)
|
||||
self?.reloadtable = true
|
||||
}
|
||||
}
|
||||
|
||||
// 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!)
|
||||
}
|
||||
}
|
||||
|
||||
func setUpController(){
|
||||
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
dataSource = channel!.people
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: itemCellId)
|
||||
tableView.reloadData()
|
||||
textField.delegate = self
|
||||
searchBar.delegate = self
|
||||
searchBar.selectedScopeButtonIndex = 0
|
||||
navigationItem.title = channel?.title
|
||||
textField.placeholder = channel?.title
|
||||
|
||||
navigationItem.title = channel?.name
|
||||
textField.placeholder = channel?.name
|
||||
|
||||
textField.addTarget(self, action: #selector(changedText(_:)), for: .editingChanged)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@objc func changedText(_ textField: UITextField){
|
||||
navigationItem.title = textField.text
|
||||
channel?.title = textField.text!
|
||||
myProtocol?.passData(for: index!, channel: channel!)
|
||||
channel?.name = textField.text!
|
||||
// myProtocol?.passData(for: index!, channel: channel!)
|
||||
}
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
@ -56,72 +98,76 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return dataSource.count
|
||||
switch activeDataSource {
|
||||
case .people:
|
||||
return dataSourcePeople.count
|
||||
case .tags:
|
||||
return dataSourceTags.count
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
if searchBar.isFirstResponder {
|
||||
if let cell = tableView.cellForRow(at: indexPath)
|
||||
{
|
||||
|
||||
if searchBar.isFirstResponder, let cell = tableView.cellForRow(at: indexPath)
|
||||
{
|
||||
if cell.accessoryType == .none{
|
||||
switch searchBar.selectedScopeButtonIndex{
|
||||
case 0:
|
||||
channel?.people.append(dataSource[indexPath.row])
|
||||
channel?.people.append(dataSourcePeople[indexPath.row].id)
|
||||
print("people = \(channel!.people)")
|
||||
case 1:
|
||||
channel?.hashtags.append(dataSource[indexPath.row])
|
||||
print("hashtags = \(channel!.hashtags)")
|
||||
channel?.tags.append(dataSourceTags[indexPath.row])
|
||||
print("hashtags = \(channel!.tags)")
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
cell.accessoryType = .checkmark
|
||||
} else {
|
||||
cell.accessoryType = .none
|
||||
|
||||
switch searchBar.selectedScopeButtonIndex{
|
||||
case 0:
|
||||
channel?.people = channel!.people.filter({ (s) -> Bool in
|
||||
!fullPeople[indexPath.row].contains(s)
|
||||
})
|
||||
// TODO: dataPass
|
||||
let filtered = channel!.people.filter{ $0 != Model.Channels.fullPeople[indexPath.row].id }
|
||||
channel?.people = filtered
|
||||
case 1:
|
||||
channel?.hashtags = channel!.hashtags.filter({ (s) -> Bool in
|
||||
!fullTags[indexPath.row].contains(s)
|
||||
})
|
||||
// TODO: dataPass
|
||||
let filtered = channel!.tags.filter{
|
||||
!fullTags[indexPath.row].contains($0)
|
||||
}
|
||||
channel?.tags = filtered
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
tableView.beginUpdates()
|
||||
dataSource.remove(at: indexPath.row)
|
||||
switch searchBar.selectedScopeButtonIndex{
|
||||
case 0:
|
||||
switch activeDataSource{
|
||||
case .people:
|
||||
channel?.people.remove(at: indexPath.row)
|
||||
// TODO: dataPass
|
||||
case 1:
|
||||
channel?.hashtags.remove(at: indexPath.row)
|
||||
// TODO: dataPass
|
||||
default:
|
||||
break
|
||||
case .tags:
|
||||
channel?.tags.remove(at: indexPath.row)
|
||||
}
|
||||
|
||||
tableView.beginUpdates()
|
||||
switch activeDataSource{
|
||||
case .people:
|
||||
dataSourcePeople.remove(at: indexPath.row)
|
||||
case .tags:
|
||||
dataSourceTags.remove(at: indexPath.row)
|
||||
}
|
||||
tableView.deleteRows(at: [indexPath], with: .none)
|
||||
tableView.endUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
|
||||
{
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: itemCellId, for: indexPath)
|
||||
|
||||
cell.textLabel?.text = dataSource[indexPath.row]
|
||||
cell.textLabel?.text = activeDataSource == .people ? "\(dataSourcePeople[indexPath.row].firstName) \(dataSourcePeople[indexPath.row].middleName) \(dataSourcePeople[indexPath.row].lastName)" : dataSourceTags[indexPath.row]
|
||||
cell.selectionStyle = .none
|
||||
|
||||
if channel!.hashtags.contains(dataSource[indexPath.row]) || channel!.people.contains(dataSource[indexPath.row])
|
||||
if activeDataSource == .tags && channel!.tags.contains(dataSourceTags[indexPath.row]) ||
|
||||
activeDataSource == .people && channel!.people.contains(dataSourcePeople[indexPath.row].id)
|
||||
{
|
||||
cell.accessoryType = .checkmark
|
||||
} else {
|
||||
@ -147,7 +193,7 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
|
||||
{
|
||||
let view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 70))
|
||||
|
||||
if flag {
|
||||
if activeDataSource == .tags {
|
||||
searchBar.selectedScopeButtonIndex = 1
|
||||
} else {
|
||||
searchBar.selectedScopeButtonIndex = 0
|
||||
@ -165,7 +211,12 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
|
||||
|
||||
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
|
||||
if searchText.isEmpty {
|
||||
dataSource = searchBar.selectedScopeButtonIndex == 0 ? fullPeople : fullTags
|
||||
switch activeDataSource {
|
||||
case .people:
|
||||
dataSourcePeople = Model.Channels.fullPeople
|
||||
case .tags:
|
||||
dataSourceTags = fullTags
|
||||
}
|
||||
tableView.reloadData()
|
||||
} else {
|
||||
filterTableView(ind: searchBar.selectedScopeButtonIndex, text: searchText)
|
||||
@ -175,12 +226,13 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
|
||||
func filterTableView(ind: Int, text: String){
|
||||
switch ind {
|
||||
case 0:
|
||||
dataSource = fullPeople.filter({ (s) -> Bool in
|
||||
s.lowercased().contains(text.lowercased())
|
||||
})
|
||||
dataSourcePeople = Model.Channels.fullPeople.filter {
|
||||
let fullName = "\($0.firstName) \($0.middleName) \($0.lastName)"
|
||||
return fullName.lowercased().contains(text.lowercased())
|
||||
}
|
||||
tableView.reloadData()
|
||||
case 1:
|
||||
dataSource = fullTags.filter({ (s) -> Bool in
|
||||
dataSourceTags = fullTags.filter({ (s) -> Bool in
|
||||
s.lowercased().contains(text.lowercased())
|
||||
})
|
||||
tableView.reloadData()
|
||||
@ -189,33 +241,62 @@ class ChannelController: UIViewController, UITableViewDelegate, UITableViewDataS
|
||||
}
|
||||
}
|
||||
|
||||
var flag = false
|
||||
|
||||
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
|
||||
activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
|
||||
if searchBar.isFirstResponder {
|
||||
dataSource = searchBar.selectedScopeButtonIndex == 0 ? fullPeople : fullTags
|
||||
flag = searchBar.selectedScopeButtonIndex == 0 ? false : true
|
||||
switch activeDataSource{
|
||||
case .people :
|
||||
dataSourcePeople = Model.Channels.fullPeople
|
||||
dataSourceTags = []
|
||||
case .tags:
|
||||
dataSourceTags = fullTags
|
||||
dataSourcePeople = []
|
||||
}
|
||||
if (!(searchBar.text?.isEmpty ?? true))
|
||||
{
|
||||
filterTableView(ind: selectedScope, text: searchBar.text!)
|
||||
}
|
||||
tableView.reloadData()
|
||||
} else if !(searchBar.isFirstResponder){
|
||||
dataSource = searchBar.selectedScopeButtonIndex == 0 ? channel!.people : channel!.hashtags
|
||||
flag = searchBar.selectedScopeButtonIndex == 0 ? false : true
|
||||
switch activeDataSource{
|
||||
case .people :
|
||||
dataSourcePeople = channel!.people.map({ (item) -> Model.Users in
|
||||
Model.Channels.fullPeopleDict[item]!
|
||||
})
|
||||
dataSourceTags = []
|
||||
case .tags:
|
||||
dataSourceTags = channel!.tags
|
||||
dataSourcePeople = []
|
||||
}
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
|
||||
dataSource = searchBar.selectedScopeButtonIndex == 0 ? channel!.people : channel!.hashtags
|
||||
flag = searchBar.selectedScopeButtonIndex == 0 ? false : true
|
||||
switch activeDataSource{
|
||||
case .people :
|
||||
dataSourcePeople = channel!.people.map({ (item) -> Model.Users in
|
||||
Model.Channels.fullPeopleDict[item]!
|
||||
})
|
||||
dataSourceTags = []
|
||||
case .tags:
|
||||
dataSourceTags = channel!.tags
|
||||
dataSourcePeople = []
|
||||
}
|
||||
activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
|
||||
dataSource = searchBar.selectedScopeButtonIndex == 0 ? fullPeople : fullTags
|
||||
flag = searchBar.selectedScopeButtonIndex == 0 ? false : true
|
||||
switch activeDataSource{
|
||||
case .people :
|
||||
dataSourcePeople = Model.Channels.fullPeople
|
||||
dataSourceTags = []
|
||||
case .tags:
|
||||
dataSourceTags = fullTags
|
||||
dataSourcePeople = []
|
||||
}
|
||||
activeDataSource = searchBar.selectedScopeButtonIndex == 0 ? .people : .tags
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,19 @@ struct ChannelData{
|
||||
class ChannelListController: UITableViewController, DataDelegate {
|
||||
|
||||
// MARK: - Output -
|
||||
var onChannelSelected: ((Channel) -> Void)?
|
||||
var onChannelSelected: ((Model.Channels) -> Void)?
|
||||
|
||||
// MARK:- filter search controller
|
||||
var filteredDataSource = [Channel]()
|
||||
// MARK: - filter search controller
|
||||
var filteredDataSource = [Model.Channels]()
|
||||
|
||||
var myProtocol: DataDelegate?
|
||||
var displayingChannel: Channel?
|
||||
var displayingChannel: Model.Channels?
|
||||
|
||||
var toReload: Bool = false {
|
||||
didSet{
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
var isFiltering: Bool {
|
||||
return searchController.isActive && !searchBarIsEmpty()
|
||||
@ -35,21 +41,24 @@ class ChannelListController: UITableViewController, DataDelegate {
|
||||
|
||||
func filterContentForSearchText(_ searchText: String, scope: String = "All")
|
||||
{
|
||||
filteredDataSource = ChannelListController.dataSource.filter({(keys : Channel) -> Bool in
|
||||
return keys.title.lowercased().contains(searchText.lowercased())
|
||||
filteredDataSource = dataSource.filter({(keys : Model.Channels) -> Bool in
|
||||
return keys.name.lowercased().contains(searchText.lowercased())
|
||||
})
|
||||
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
func passData(for row: Int, channel: Channel) {
|
||||
ChannelListController.dataSource[row] = channel
|
||||
func passData(for row: Int, channel: Model.Channels) {
|
||||
// dataSource[row] = channel
|
||||
}
|
||||
|
||||
var searchController = UISearchController(searchResultsController: nil)
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
Model.usersAllGet()
|
||||
|
||||
setUpNavigationBar()
|
||||
navigationItem.title = "Channels"
|
||||
searchController.searchResultsUpdater = self
|
||||
@ -60,49 +69,48 @@ class ChannelListController: UITableViewController, DataDelegate {
|
||||
}
|
||||
|
||||
func setUpNavigationBar(){
|
||||
navigationController?.navigationItem.largeTitleDisplayMode = .always
|
||||
navigationItem.largeTitleDisplayMode = .always
|
||||
navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addChannel))]
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool)
|
||||
override func viewDidAppear(_ animated: Bool)
|
||||
{
|
||||
super.viewWillAppear(animated)
|
||||
super.viewDidAppear(animated)
|
||||
searchController.isActive = false
|
||||
tableView.reloadData()
|
||||
askForUpdates()
|
||||
}
|
||||
|
||||
private func askForUpdates(){
|
||||
Model.channelsList { [weak self] (channels) in
|
||||
self?.dataSource = [ChannelListController.generalChannel] + channels
|
||||
self?.toReload = true
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(true)
|
||||
askForUpdates()
|
||||
}
|
||||
|
||||
@objc func addChannel()
|
||||
{
|
||||
// insertion
|
||||
tableView.beginUpdates()
|
||||
ChannelListController.dataSource.insert(Channel(title: "Untitled", subtitle: "No", hashtags: [], people: [], posts: []), at: 1)
|
||||
tableView.insertRows(at: [IndexPath(row: 1, section: 0)], with: .none)
|
||||
tableView.endUpdates()
|
||||
|
||||
// editing mode is on automatically
|
||||
let vc = storyboard?.instantiateViewController(withIdentifier: channelControllerId) as! ChannelController
|
||||
vc.index = 1
|
||||
vc.myProtocol = self
|
||||
vc.channel = ChannelListController.dataSource[1]
|
||||
vc.channel = Model.Channels(people: [], name: "Untitled", tags: [])
|
||||
navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
static var dataSource : [Channel] = [
|
||||
Channel(title: "General", subtitle: "All posts", hashtags: ["All"], people: ["All"], posts: []),
|
||||
Channel(title: "Title", subtitle: "subtitle", hashtags: ["# sad", "# happy"], people: ["Seva", "Andrey"], posts: [Post(dataArray: [.text("Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard.")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05")]),
|
||||
Channel(title: "Title2", subtitle: "subtitle2", hashtags: ["# studyhard", "# university"], people: ["Pasha", "Olya", "Andrey", "Ilya"], posts:
|
||||
[
|
||||
Post(dataArray: [.text("L'avantage du Lorem Ipsum sur un texte générique comme 'Du texte. Du texte. Du texte.' est qu'il possède une distribution de lettres plus ou moins normale.")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05"),
|
||||
Post(dataArray: [.text("par accident, souvent intentionnellement (histoire d'y rajouter de petits clins d'oeil, voire des phrases embarassantes).")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05")
|
||||
]),
|
||||
Channel(title: "Title3", subtitle: "subtitle3", hashtags: ["# lol", "# meme", "# hehe"], people: ["Superman"], posts: [Post(dataArray: [.text("Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié.")], from: User(name: "vbogomazova", id: 2, fullName: "Богомазова Вероника Львовна"), date: "14.02.19 в 12:05")])
|
||||
]
|
||||
static let generalChannel = Model.Channels(people: [], name: "General", id: -1, tags: [])
|
||||
|
||||
var dataSource : [Model.Channels] = [ ChannelListController.generalChannel ]
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
if isFiltering {
|
||||
return filteredDataSource.count
|
||||
} else {
|
||||
return ChannelListController.dataSource.count
|
||||
return dataSource.count
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,11 +121,11 @@ class ChannelListController: UITableViewController, DataDelegate {
|
||||
|
||||
|
||||
if isFiltering{
|
||||
cell.textLabel?.text = filteredDataSource[indexPath.row].title
|
||||
cell.detailTextLabel?.text = filteredDataSource[indexPath.row].subtitle
|
||||
cell.textLabel?.text = filteredDataSource[indexPath.row].name
|
||||
cell.detailTextLabel?.text = filteredDataSource[indexPath.row].tags.reduce(String(), { (r, next) -> String in "\(r) \(next)" })
|
||||
} else {
|
||||
cell.textLabel?.text = ChannelListController.dataSource[indexPath.row].title
|
||||
cell.detailTextLabel?.text = ChannelListController.dataSource[indexPath.row].subtitle
|
||||
cell.textLabel?.text = dataSource[indexPath.row].name
|
||||
cell.detailTextLabel?.text = dataSource[indexPath.row].tags.reduce(String(), { (r, next) -> String in "\(r) \(next)" })
|
||||
}
|
||||
|
||||
return cell
|
||||
@ -140,24 +148,29 @@ class ChannelListController: UITableViewController, DataDelegate {
|
||||
let vc = self?.storyboard?.instantiateViewController(withIdentifier: channelControllerId) as! ChannelController
|
||||
vc.index = indexPath.row
|
||||
vc.myProtocol = self!
|
||||
vc.channel = ChannelListController.dataSource[indexPath.row]
|
||||
vc.channel = self?.dataSource[indexPath.row]
|
||||
self?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
editButton.backgroundColor = .green
|
||||
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
|
||||
if (ChannelListController.dataSource[indexPath.row] == self!.displayingChannel!)
|
||||
|
||||
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: ChannelListController.dataSource[0])
|
||||
self?.myProtocol?.passData(for: 0, channel: self!.dataSource[0])
|
||||
}
|
||||
self?.tableView.beginUpdates()
|
||||
ChannelListController.dataSource.remove(at: indexPath.row)
|
||||
self?.dataSource.remove(at: indexPath.row)
|
||||
self?.tableView.deleteRows(at: [indexPath], with: .none)
|
||||
self?.tableView.endUpdates()
|
||||
}
|
||||
deleteButton.backgroundColor = .red
|
||||
|
||||
deleteButton.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
|
||||
|
||||
return [editButton, deleteButton]
|
||||
}
|
||||
@ -170,7 +183,7 @@ class ChannelListController: UITableViewController, DataDelegate {
|
||||
myProtocol?.passData(for: 0, channel: filteredDataSource[indexPath.row])
|
||||
navigationController?.popViewController(animated: true)
|
||||
} else {
|
||||
myProtocol?.passData(for: 0, channel: ChannelListController.dataSource[indexPath.row])
|
||||
myProtocol?.passData(for: 0, channel: dataSource[indexPath.row])
|
||||
navigationController?.popViewController(animated: true)
|
||||
//onChannelSelected?(ChannelListController.dataSource[indexPath.row])
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ import UIKit
|
||||
final class ChannelsCoordinator{
|
||||
|
||||
// MARK: - Properties
|
||||
private var channel: Channel { didSet { updateInterfaces() } }
|
||||
private var channel: Model.Channels { didSet { updateInterfaces() } }
|
||||
private weak var navigationController: UINavigationController?
|
||||
|
||||
// MARK:- Init
|
||||
init(currentChannel: Channel, navigationController: UINavigationController) {
|
||||
init(currentChannel: Model.Channels, navigationController: UINavigationController) {
|
||||
self.channel = currentChannel
|
||||
self.navigationController = navigationController
|
||||
}
|
||||
|
@ -11,7 +11,8 @@ import TinyConstraints
|
||||
|
||||
class FullPostController: UITableViewController {
|
||||
|
||||
var post: Post?
|
||||
var post: Model.Posts?
|
||||
var type: HeaderType = .NONE
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
@ -20,13 +21,11 @@ class FullPostController: UITableViewController {
|
||||
|
||||
setUpNavigationBar()
|
||||
tableView.separatorStyle = .none
|
||||
|
||||
|
||||
}
|
||||
|
||||
func setUpNavigationBar(){
|
||||
navigationController?.navigationBar.prefersLargeTitles = false
|
||||
navigationItem.title = "\(post?.fromUser.login ?? "")"
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
navigationItem.title = "\(post?.authorId ?? 0)"
|
||||
navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(self.options))]
|
||||
}
|
||||
|
||||
@ -83,7 +82,7 @@ class FullPostController: UITableViewController {
|
||||
case 0:
|
||||
return 1
|
||||
case 1:
|
||||
return post?.comments.count ?? 0
|
||||
return 0
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
@ -95,7 +94,20 @@ class FullPostController: UITableViewController {
|
||||
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: postCellId) as! PostViewCell
|
||||
|
||||
cell.fill(with: post!.dataArray, true, post: post!)
|
||||
|
||||
cell.fill(with: PostCellData.create(with: post!.body), true, post: post!)
|
||||
|
||||
switch type {
|
||||
case .NEWS:
|
||||
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:
|
||||
break
|
||||
}
|
||||
|
||||
cell.selectionStyle = .none
|
||||
return cell
|
||||
}
|
||||
|
@ -10,10 +10,15 @@ import UIKit
|
||||
import Cartography
|
||||
import Marklight
|
||||
import TinyConstraints
|
||||
import WSTagsField
|
||||
|
||||
class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
|
||||
@IBOutlet weak var view1: UIView!
|
||||
|
||||
@IBOutlet weak var viewForTags: UIView!
|
||||
|
||||
fileprivate let tagsField = WSTagsField()
|
||||
// Keep strong instance of the `NSTextStorage` subclass
|
||||
let textStorage = MarklightTextStorage()
|
||||
|
||||
@ -21,6 +26,8 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
var myProtocol: NewPostDelegate?
|
||||
|
||||
static var draft: String = ""
|
||||
static var hashTagsDraft: [String] = []
|
||||
|
||||
var textView: UITextView!
|
||||
|
||||
// buttons for attaching images
|
||||
@ -46,9 +53,42 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
override func viewDidLoad()
|
||||
{
|
||||
super.viewDidLoad()
|
||||
//createTimerForUpdates()
|
||||
|
||||
setUpMD()
|
||||
setUpTextView()
|
||||
setUpAccessoryView()
|
||||
setUpTagsView()
|
||||
}
|
||||
|
||||
func setUpTagsView(){
|
||||
tagsField.frame = viewForTags.bounds
|
||||
viewForTags.addSubview(tagsField)
|
||||
|
||||
// tagsField.translatesAutoresizingMaskIntoConstraints = false
|
||||
// tagsField.heightAnchor.constraint(lessThanOrEqualToConstant: 150).isActive = true
|
||||
|
||||
tagsField.cornerRadius = 3.0
|
||||
tagsField.spaceBetweenLines = 10
|
||||
tagsField.spaceBetweenTags = 10
|
||||
|
||||
//tagsField.numberOfLines = 3
|
||||
//tagsField.maxHeight = 100.0
|
||||
|
||||
tagsField.layoutMargins = UIEdgeInsets(top: 2, left: 6, bottom: 2, right: 6)
|
||||
tagsField.contentInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) //old padding
|
||||
|
||||
tagsField.placeholder = "Enter a tag"
|
||||
tagsField.placeholderColor = #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)
|
||||
tagsField.placeholderAlwaysVisible = true
|
||||
tagsField.backgroundColor = #colorLiteral(red: 0.937254902, green: 0.937254902, blue: 0.9568627451, alpha: 1)
|
||||
tagsField.returnKeyType = .next
|
||||
tagsField.delimiter = ""
|
||||
|
||||
tagsField.textDelegate = self
|
||||
tagsField.acceptTagOption = .space
|
||||
|
||||
textFieldEvents()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
@ -57,6 +97,8 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
navigationController?.navigationBar.prefersLargeTitles = false
|
||||
navigationItem.title = "New post"
|
||||
textView.text = NewPostViewController.draft
|
||||
tagsField.addTags(NewPostViewController.hashTagsDraft)
|
||||
|
||||
}
|
||||
|
||||
func setUpAccessoryView(){
|
||||
@ -148,23 +190,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
|
||||
@objc func addMathBrackets()
|
||||
{
|
||||
if textView.text.count != 0 && textView.text.last != "\n" {
|
||||
textView.insertText("\n\\[\n ")
|
||||
}
|
||||
else {
|
||||
textView.insertText("\\[\n ")
|
||||
}
|
||||
|
||||
if let selectedRange = textView.selectedTextRange
|
||||
{
|
||||
textView.insertText("\n\\]\n")
|
||||
|
||||
if let newPosition = textView.position(from: selectedRange.start, offset: 0)
|
||||
{
|
||||
// set the new position
|
||||
textView.selectedTextRange = textView.textRange(from: newPosition, to: newPosition)
|
||||
}
|
||||
}
|
||||
// nothing
|
||||
}
|
||||
|
||||
func setUpMD(){
|
||||
@ -178,6 +204,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
let layoutManager = NSLayoutManager()
|
||||
|
||||
// Assign the `UITextView`'s `NSLayoutManager` to the `NSTextStorage` subclass
|
||||
//textStorage.addLayoutManager(textView.layoutManager)
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
|
||||
let textContainer = NSTextContainer()
|
||||
@ -186,13 +213,12 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
textView = UITextView(frame: view.bounds, textContainer: textContainer)
|
||||
}
|
||||
|
||||
var indexOfPost = 0
|
||||
// MARK:- new post
|
||||
@objc func newPost(){
|
||||
let p = Post(dataArray: [.text(textView.text)], from: User(name: "Сева", id: 5, fullName: "Сева Леонидович"), date: "12.01.19")
|
||||
|
||||
|
||||
Model.createAndPublish(body: [Model.Attachments(markdown: textView!.text)], tags: tagsField.tags.map { $0.text })
|
||||
// adding row to uiTableView after adding new post
|
||||
myProtocol?.addPost(post: p)
|
||||
// myProtocol?.addPost(post: p)
|
||||
moveBackToParentVC()
|
||||
// somewhere here i will be sending server notifications about new post arrival
|
||||
}
|
||||
@ -205,6 +231,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
[weak self]
|
||||
_ in
|
||||
NewPostViewController.draft = self?.textView.text ?? ""
|
||||
NewPostViewController.hashTagsDraft = self?.tagsField.tags.map { $0.text } ?? []
|
||||
self?.moveBackToParentVC()
|
||||
}
|
||||
|
||||
@ -213,6 +240,7 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
[weak self] (_)
|
||||
in
|
||||
NewPostViewController.draft = ""
|
||||
NewPostViewController.hashTagsDraft = []
|
||||
self?.moveBackToParentVC()
|
||||
}
|
||||
|
||||
@ -252,4 +280,42 @@ class NewPostViewController: UIViewController, UITextViewDelegate {
|
||||
rect.size.height = rect.size.height + textView.textContainerInset.bottom
|
||||
textView.scrollRectToVisible(rect, animated: animated)
|
||||
}
|
||||
|
||||
fileprivate func textFieldEvents() {
|
||||
tagsField.onDidAddTag = { _, _ in
|
||||
print("onDidAddTag")
|
||||
}
|
||||
|
||||
tagsField.onDidRemoveTag = { _, _ in
|
||||
print("onDidRemoveTag")
|
||||
}
|
||||
|
||||
tagsField.onDidChangeText = { _, text in
|
||||
print("onDidChangeText")
|
||||
}
|
||||
|
||||
tagsField.onDidChangeHeightTo = { _, height in
|
||||
print("HeightTo \(height)")
|
||||
}
|
||||
|
||||
tagsField.onDidSelectTagView = { _, tagView in
|
||||
print("Select \(tagView)")
|
||||
}
|
||||
|
||||
tagsField.onDidUnselectTagView = { _, tagView in
|
||||
print("Unselect \(tagView)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension NewPostViewController: UITextFieldDelegate {
|
||||
|
||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||
if textField == tagsField {
|
||||
textView.becomeFirstResponder()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,24 +11,54 @@ import TinyConstraints
|
||||
import Cartography
|
||||
|
||||
protocol UpdateableWithChannel: class {
|
||||
var channel: Channel? { get set }
|
||||
var channel: Model.Channels? { get set }
|
||||
}
|
||||
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
|
||||
{
|
||||
func passData(for row: Int, channel: Channel) {
|
||||
self.channel = channel
|
||||
func passData(for row: Int, channel: Model.Channels) {
|
||||
if channel.id == -1{
|
||||
self.channel = nil
|
||||
} else {
|
||||
self.channel = channel
|
||||
}
|
||||
}
|
||||
|
||||
var channel: Channel?{
|
||||
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 posts: [Model.Posts]? {
|
||||
didSet{
|
||||
news.dataSourse = channel?.posts ?? []
|
||||
navigationItem.title = channel?.title ?? ""
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var channel: Model.Channels? {
|
||||
didSet {
|
||||
navigationItem.title = channel?.name ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,37 +66,51 @@ class NewsController: UITableViewController, UISearchControllerDelegate, NewPost
|
||||
var onSelectChannel: (() -> Void)?
|
||||
|
||||
func addPost(post: Post) {
|
||||
news.dataSourse.insert(post, at: 0)
|
||||
//news.dataSourse.insert(post, at: 0)
|
||||
}
|
||||
|
||||
var searchController = UISearchController(searchResultsController: nil)
|
||||
|
||||
var news = NewsVC()
|
||||
|
||||
var refreshContr = UIRefreshControl()
|
||||
|
||||
override func viewDidLoad()
|
||||
{
|
||||
super.viewDidLoad()
|
||||
channel = ChannelListController.dataSource[0]
|
||||
|
||||
navigationItem.title = "Loading ..."
|
||||
tableView.refreshControl = refreshContr
|
||||
// Configure Refresh Control
|
||||
refreshContr.addTarget(self, action: #selector(refreshPostsData(_:)), for: .valueChanged)
|
||||
|
||||
tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
|
||||
|
||||
searchController.delegate = self
|
||||
searchController.obscuresBackgroundDuringPresentation = false
|
||||
navigationItem.searchController = searchController
|
||||
definesPresentationContext = true
|
||||
searchController.searchBar.placeholder = "Search anything"
|
||||
// setUpSearchContr()
|
||||
|
||||
news.dataSourse = channel!.posts
|
||||
news.viewController = self
|
||||
|
||||
news.type = .NONE
|
||||
news.type = .NEWS
|
||||
|
||||
setUpNavigationItemsforPosts()
|
||||
|
||||
//setUpBanner()
|
||||
}
|
||||
|
||||
func setUpSearchContr(){
|
||||
searchController.delegate = self
|
||||
searchController.obscuresBackgroundDuringPresentation = false
|
||||
navigationItem.searchController = searchController
|
||||
definesPresentationContext = true
|
||||
searchController.searchBar.placeholder = "Search anything"
|
||||
}
|
||||
|
||||
@objc func refreshPostsData( _ ff: UIRefreshControl){
|
||||
decideWhatChannelDisplay()
|
||||
}
|
||||
|
||||
deinit {
|
||||
print("news clear")
|
||||
}
|
||||
|
||||
let label : UILabel = {
|
||||
let label = UILabel()
|
||||
@ -82,7 +126,31 @@ class NewsController: UITableViewController, UISearchControllerDelegate, NewPost
|
||||
super.viewWillAppear(animated)
|
||||
searchController.isActive = false
|
||||
// TODO:- display something if no posts are availiable
|
||||
tableView.reloadData()
|
||||
|
||||
decideWhatChannelDisplay()
|
||||
|
||||
// tableView.reloadData()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Model.getLast { [weak self] in
|
||||
self?.posts = $0.posts
|
||||
self?.dictionary = $0.users
|
||||
self?.refreshContr.endRefreshing()
|
||||
self?.navigationItem.title = "General"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func setUpNavigationItemsforPosts(){
|
||||
|
@ -7,14 +7,40 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MarkdownKit
|
||||
|
||||
struct PostCellData{
|
||||
var attributedData = NSAttributedString()
|
||||
|
||||
static func create(with attachments: [Model.Attachments]) -> NSAttributedString{
|
||||
var markdown = ""
|
||||
|
||||
attachments.forEach { (attachment) in markdown.append(attachment.markdown) }
|
||||
|
||||
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)
|
||||
|
||||
return markdownParser.parse(markdown)
|
||||
}
|
||||
}
|
||||
|
||||
class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
|
||||
|
||||
var dataSourse: [Post] = []
|
||||
var dataSourse: [Model.Posts] = [] {
|
||||
didSet {
|
||||
cellDataSourse = []
|
||||
dataSourse.forEach { (item) in
|
||||
cellDataSourse.append(PostCellData(attributedData: PostCellData.create(with: item.body)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cellDataSourse: [PostCellData] = []
|
||||
|
||||
var type: HeaderType = .NONE
|
||||
|
||||
var viewController: UIViewController?
|
||||
weak var viewController: UIViewController?
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return 1
|
||||
@ -24,7 +50,7 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
|
||||
{
|
||||
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)
|
||||
}
|
||||
@ -37,7 +63,21 @@ class NewsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
|
||||
{
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: postCellId, for: indexPath) as! PostViewCell
|
||||
|
||||
cell.fill(with: dataSourse[indexPath.row].dataArray, false, post: dataSourse[indexPath.row])
|
||||
cell.fill(with: cellDataSourse[indexPath.row].attributedData, false, post: dataSourse[indexPath.row])
|
||||
|
||||
switch type {
|
||||
case .NEWS:
|
||||
cell.onUserDisplay = { [weak self] (id) in
|
||||
let vc = self?.viewController!.storyboard!.instantiateViewController(withIdentifier: profileViewController) as! ProfileViewController
|
||||
vc.idProfile = id
|
||||
self?.viewController!.navigationController!.pushViewController(vc, animated: true)
|
||||
}
|
||||
case .NONE:
|
||||
cell.onUserDisplay = { (id) in
|
||||
print("tapped when profile is open already \(id)")
|
||||
}
|
||||
}
|
||||
|
||||
cell.selectionStyle = .none
|
||||
return cell
|
||||
}
|
||||
|
@ -13,12 +13,14 @@ import TinyConstraints
|
||||
|
||||
class PostViewCell: UITableViewCell
|
||||
{
|
||||
let nameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
|
||||
label.text = "vbogomazova"
|
||||
label.font = UIFont.boldSystemFont(ofSize: 16)
|
||||
return label
|
||||
var onUserDisplay: ((Int)->())?
|
||||
|
||||
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
|
||||
}()
|
||||
|
||||
let fullNameLabel: UILabel = {
|
||||
@ -29,7 +31,7 @@ class PostViewCell: UITableViewCell
|
||||
return label
|
||||
}()
|
||||
|
||||
let commentsLabel: UILabel = {
|
||||
let timeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFont.systemFont(ofSize: 12)
|
||||
label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
|
||||
@ -51,50 +53,52 @@ class PostViewCell: UITableViewCell
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func createTextView(with text: String) -> UITextView
|
||||
func createTextView(with text: NSAttributedString, _ isSelectable: Bool) -> UITextView
|
||||
{
|
||||
let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
|
||||
let markdown = text
|
||||
markdownParser.enabledElements = .disabledAutomaticLink
|
||||
markdownParser.header.fontIncrease = 6
|
||||
markdownParser.code.textBackgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
|
||||
|
||||
let textView = UITextView()
|
||||
textView.isScrollEnabled = false
|
||||
textView.isEditable = false
|
||||
textView.isUserInteractionEnabled = false
|
||||
textView.attributedText = markdownParser.parse(markdown)
|
||||
if isSelectable {
|
||||
//textView.isUserInteractionEnabled = false
|
||||
textView.isSelectable = true
|
||||
} else {
|
||||
textView.isUserInteractionEnabled = false
|
||||
}
|
||||
|
||||
textView.attributedText = text
|
||||
return textView
|
||||
}
|
||||
|
||||
var views: [UIView] = []
|
||||
var data : [UIImage] = []
|
||||
var post: Post?
|
||||
var post: Model.Posts?
|
||||
|
||||
func fill(with info: [Media], _ isFullVersoin: Bool, post: Post)
|
||||
func fill(with info: NSAttributedString, _ isFullVersoin: Bool, post: Model.Posts)
|
||||
{
|
||||
self.post = post
|
||||
// important
|
||||
contentView.subviews.forEach({ $0.removeFromSuperview() })
|
||||
|
||||
data = []
|
||||
views = []
|
||||
for item in info.enumerated()
|
||||
{
|
||||
switch item.element
|
||||
{
|
||||
case .text(let text):
|
||||
views.append(createTextView(with: text))
|
||||
case .image(let images):
|
||||
self.data = images
|
||||
default:
|
||||
break
|
||||
}
|
||||
views.append(createTextView(with: info, isFullVersoin))
|
||||
|
||||
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)"
|
||||
}
|
||||
else {
|
||||
fullNameLabel.text = "\(post.authorId)"
|
||||
}
|
||||
|
||||
setUpInStackView(isFullVersoin)
|
||||
}
|
||||
|
||||
var hashtags = [String]()
|
||||
|
||||
func setUpInStackView(_ full : Bool){
|
||||
|
||||
hashtags = post!.tags
|
||||
|
||||
let nameStackView = UIStackView(arrangedSubviews: [nameLabel, fullNameLabel])
|
||||
nameStackView.axis = .vertical
|
||||
contentView.addSubview(nameStackView)
|
||||
@ -113,7 +117,7 @@ class PostViewCell: UITableViewCell
|
||||
scrollView.showsHorizontalScrollIndicator = false
|
||||
|
||||
var buttons: [UIButton] = []
|
||||
for hash in post!.hashtags {
|
||||
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)
|
||||
@ -143,7 +147,13 @@ class PostViewCell: UITableViewCell
|
||||
contentView.addSubview(mainView)
|
||||
mainView.edgesToSuperview(excluding: [.top, .bottom])
|
||||
mainView.topToBottom(of: nameStackView, offset: 5)
|
||||
mainView.height(30)
|
||||
|
||||
// TODO:- change!!!!!!!!!!!!
|
||||
if hashtags.isEmpty{
|
||||
mainView.height(0)
|
||||
} else {
|
||||
mainView.height(30)
|
||||
}
|
||||
|
||||
let stackView = MyStackView(arrangedSubviews: views)
|
||||
stackView.isFull = full
|
||||
@ -157,13 +167,19 @@ class PostViewCell: UITableViewCell
|
||||
|
||||
stackView.edgesToSuperview(excluding: [.top, .bottom], insets: .left(16) + .right(16))
|
||||
|
||||
let commentsSharesStackView = UIStackView(arrangedSubviews: [ commentsLabel, shareButton])
|
||||
let commentsSharesStackView = UIStackView(arrangedSubviews: [ timeLabel, shareButton])
|
||||
contentView.addSubview(commentsSharesStackView)
|
||||
|
||||
commentsLabel.text = "14.02.19 в 23:00"
|
||||
timeLabel.text = post!.convertDateFormatter()
|
||||
|
||||
commentsSharesStackView.axis = .horizontal
|
||||
commentsSharesStackView.distribution = .equalSpacing
|
||||
commentsSharesStackView.edgesToSuperview(excluding: .top, insets: .bottom(10) + .left(16) + .right(16))
|
||||
stackView.bottomToTop(of: commentsSharesStackView)
|
||||
}
|
||||
|
||||
@objc func displayProfile(){
|
||||
print("buttonTapped")
|
||||
onUserDisplay?(post!.authorId)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
//
|
||||
// SimplifiedChannelsList.swift
|
||||
// GDproject
|
||||
//
|
||||
// Created by cstore on 13/03/2019.
|
||||
// Copyright © 2019 drHSE. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
/// class for ADDing person to existing (or new) channel: like playlist in itunes
|
||||
import UIKit
|
||||
import TinyConstraints
|
||||
|
||||
class SimplifiedChannelsList: UITableViewController {
|
||||
|
||||
var user: Model.Users?
|
||||
|
||||
var dataSource: [Model.Channels]?{
|
||||
didSet{
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setUpNavigationButtons()
|
||||
navigationItem.title = "All channels"
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
self.navigationItem.setHidesBackButton(true, animated:true)
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
Model.channelsList { [weak self] (channels) in
|
||||
self?.dataSource = channels
|
||||
}
|
||||
}
|
||||
|
||||
func setUpNavigationButtons(){
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelAction))
|
||||
}
|
||||
|
||||
func completedActions(with channel: Model.Channels){
|
||||
Model.updateChannel(with: channel)
|
||||
cancelAction()
|
||||
}
|
||||
|
||||
@objc func cancelAction(){
|
||||
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)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let viewHeader = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 30))
|
||||
viewHeader.backgroundColor = .white
|
||||
let label = UILabel()
|
||||
|
||||
label.text = "All channels"
|
||||
label.font = UIFont.boldSystemFont(ofSize: 22)
|
||||
label.textColor = .black
|
||||
|
||||
viewHeader.addSubview(label)
|
||||
label.edgesToSuperview(insets: .left(16))
|
||||
return viewHeader
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
return 30
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return dataSource?.count ?? 0
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
var channel = dataSource![indexPath.row]
|
||||
channel.people.append(user!.id)
|
||||
completedActions(with: channel)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
|
||||
|
||||
cell.textLabel?.text = dataSource![indexPath.row].name
|
||||
cell.detailTextLabel?.text = "hello"
|
||||
|
||||
return cell
|
||||
}
|
||||
}
|
@ -2,9 +2,10 @@ import UIKit
|
||||
|
||||
class TabbarCoordinator{
|
||||
var window: UIWindow!
|
||||
|
||||
|
||||
func start(){
|
||||
window.rootViewController = UIStoryboard.tabBarController()
|
||||
let tabbar = UIStoryboard.tabBarController()
|
||||
window.rootViewController = tabbar
|
||||
}
|
||||
|
||||
init(window: UIWindow) {
|
||||
|
48
GDproject/Controller/Log In/LogInCoordinator.swift
Normal file
48
GDproject/Controller/Log In/LogInCoordinator.swift
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
|
||||
}
|
@ -12,6 +12,19 @@ class LogInViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var mailTextField: UITextField!
|
||||
|
||||
@IBOutlet weak var indicatorView: UIActivityIndicatorView!
|
||||
|
||||
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?
|
||||
@ -40,14 +53,10 @@ class LogInViewController: UIViewController {
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
// MARK:- uncomment when mail registration will be availiable
|
||||
//self.navigationController?.setNavigationBarHidden(true, animated: animated)
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
// MARK:- uncomment when mail registration will be availiable
|
||||
//self.navigationController?.setNavigationBarHidden(false, animated: animated)
|
||||
}
|
||||
|
||||
private func configureTapgesture(){
|
||||
@ -62,16 +71,20 @@ class LogInViewController: UIViewController {
|
||||
@objc func activateLogInProcess(){
|
||||
if logInButton.isEnabled {
|
||||
// MARK:- when log in is succeeded do I need to go there?
|
||||
let vc = storyboard!.instantiateViewController(withIdentifier: newsController) as! NewsController
|
||||
present(vc, animated: true) {
|
||||
print("logged in")
|
||||
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)
|
||||
}
|
||||
DataStorage.standard.setIsLoggedIn(value: true)
|
||||
view.endEditing(true)
|
||||
}
|
||||
}
|
||||
|
||||
func setUpView(){
|
||||
indicatorView.isHidden = true
|
||||
mailTextField.delegate = self
|
||||
view.addSubview(keyboardBar)
|
||||
|
||||
@ -80,6 +93,10 @@ class LogInViewController: UIViewController {
|
||||
|
||||
setUpBarComponents()
|
||||
|
||||
configureKeyboardBehavior()
|
||||
}
|
||||
|
||||
func configureKeyboardBehavior(){
|
||||
bottomConstraint = NSLayoutConstraint(item: keyboardBar, attribute: .bottom, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
|
||||
view.addConstraint(bottomConstraint!)
|
||||
|
||||
@ -115,9 +132,7 @@ class LogInViewController: UIViewController {
|
||||
|
||||
UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
|
||||
self.view.layoutIfNeeded()
|
||||
}) { (completed) in
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -39,15 +39,14 @@ class BasicInfoController: UIViewController, UITableViewDelegate, UITableViewDat
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
if indexPath.row == 0 {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: basicInfoCellId, for: indexPath) as! BasicInfoCell
|
||||
cell.fill(title: dataSourse[indexPath.section].title)
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
|
||||
cell.textLabel?.text = dataSourse[indexPath.section].title
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
cell.selectionStyle = .none
|
||||
return cell
|
||||
} else {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: infoCellId, for: indexPath) as! InfoCell
|
||||
cell.fill(title: dataSourse[indexPath.section].sectionData[indexPath.row - 1])
|
||||
cell.selectionStyle = .none
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
|
||||
cell.textLabel?.text = dataSourse[indexPath.section].sectionData[indexPath.row - 1]
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
@ -30,27 +30,53 @@ 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")]
|
||||
|
||||
func fill(with user: User){
|
||||
self.facultyLabel.text = user.faculty ?? ""
|
||||
self.nameLabel.text = "\(user.initials.name) \(user.initials.optional ?? "")"
|
||||
self.surnameLabel.text = user.initials.surname
|
||||
self.profileImageView.image = #imageLiteral(resourceName: "kitten").roundedImage
|
||||
self.placeLabel.text = user.placeOfWork
|
||||
func fill(with user: Model.Users){
|
||||
self.facultyLabel.text = "Студент: Факультет Компьютерных Наук"
|
||||
self.nameLabel.text = "\(user.firstName) \(user.middleName)"
|
||||
self.surnameLabel.text = "\(user.lastName)"
|
||||
self.profileImageView.image = protoDictionary[user.id]?.roundedImage
|
||||
self.placeLabel.text = "📍Москва, Кочновский пр.3"
|
||||
if user.id == DataStorage.standard.getUserId() {
|
||||
newMessageButton.isHidden = true
|
||||
} else {
|
||||
newMessageButton.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
var user: User = User(surname: "Богомазова", name: "Вероника", optional: "Львовна", emailName: "vbogomazova", id: 2, place: "📍Москва, Кочновский пр. 3", faculty: "Методист: Факультет Компьютерных наук")
|
||||
var user: Model.Users? {
|
||||
didSet {
|
||||
self.fill(with: user!)
|
||||
Model.getPostsForUser(with: user!.id) { [weak self] (posts) in
|
||||
self?.dataSourse = posts
|
||||
}
|
||||
navigationItem.title = "\(user!.firstName) \(user!.lastName)"
|
||||
}
|
||||
}
|
||||
|
||||
let basicInfo = BasicInfoController()
|
||||
let posts = NewsVC()
|
||||
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()
|
||||
|
||||
posts.dataSourse = [Post(dataArray: [.text("Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. comme Aldus PageMaker. est qu'il possède une distribution de lettres plus ou moins normale, et en tout cas comparable avec celle du français standard. De nombreuses suites logicielles de mise en page ou éditeurs de sites Web ont fait du Lorem Ipsum leur faux texte par défaut, et une recherche pour 'Lorem Ipsum' vous conduira vers de nombreux sites qui n'en sont encore qu'à leur phase de construction. Plusieurs versions sont apparues avec le temps, parfois par accident, souvent intentionnellement (histoire d'y rajouter de petits clins d'oeil, voire des phrases embarassantes).")]), Post(dataArray: [.text("Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment, par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker. .")])]
|
||||
|
||||
// basicInfo.dataSourse =
|
||||
|
||||
posts.viewController = self
|
||||
posts.type = .NONE
|
||||
@ -65,19 +91,36 @@ class ProfileViewController: UIViewController
|
||||
|
||||
posts.viewController = self
|
||||
|
||||
fill(with: user)
|
||||
tableView.delegate = posts
|
||||
tableView.dataSource = posts
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
var idProfile: Int?
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
if idProfile == nil {
|
||||
idProfile = DataStorage.standard.getUserId()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
setUpNavigarionBar()
|
||||
}
|
||||
|
||||
func setUpNavigarionBar(){
|
||||
navigationController?.navigationBar.prefersLargeTitles = true
|
||||
navigationItem.title = user.login
|
||||
//navigationItem.title = "\(user?.id ?? 0)"
|
||||
let uibarbutton = UIBarButtonItem(title: "More", style: .plain, target: self, action: #selector(showInformation))
|
||||
navigationItem.rightBarButtonItems = [uibarbutton]
|
||||
navigationItem.largeTitleDisplayMode = .always
|
||||
@ -95,7 +138,21 @@ class ProfileViewController: UIViewController
|
||||
// saved
|
||||
|
||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
let editAction = UIAlertAction(title: "Edit profile", style: .default)
|
||||
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
|
||||
|
||||
@ -104,17 +161,24 @@ class ProfileViewController: UIViewController
|
||||
}
|
||||
|
||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
|
||||
let shareAction = UIAlertAction(title: "Share", style: .default)
|
||||
let logoutAction = UIAlertAction(title: "Log out", style: .destructive)
|
||||
{
|
||||
(_) in
|
||||
DataStorage.standard.setIsLoggedIn(value: false, with: 0)
|
||||
}
|
||||
|
||||
optionMenu.addAction(editAction)
|
||||
optionMenu.addAction(channelAction)
|
||||
optionMenu.addAction(settingsAction)
|
||||
optionMenu.addAction(copyLink)
|
||||
optionMenu.addAction(shareAction)
|
||||
optionMenu.addAction(logoutAction)
|
||||
optionMenu.addAction(cancelAction)
|
||||
|
||||
self.present(optionMenu, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
deinit {
|
||||
print("profile clear")
|
||||
}
|
||||
|
||||
@IBAction func valueChanged(_ sender: UISegmentedControl) {
|
||||
let index = sender.selectedSegmentIndex
|
||||
|
59
GDproject/Controller/RepeatingTimer.swift
Normal file
59
GDproject/Controller/RepeatingTimer.swift
Normal file
@ -0,0 +1,59 @@
|
||||
/// 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()
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/**
|
||||
_DataStorage_ class is aimed to store user private settings
|
||||
@ -16,24 +17,37 @@ class DataStorage{
|
||||
|
||||
private init(){}
|
||||
|
||||
//weak var coordinator: LogInCoordinator?
|
||||
static let standard = DataStorage()
|
||||
|
||||
// add channel
|
||||
|
||||
// delete channel
|
||||
|
||||
/**
|
||||
Function for setting log in status of user
|
||||
*/
|
||||
func setIsLoggedIn(value: Bool){
|
||||
func setIsLoggedIn(value: Bool, with id: Int){
|
||||
UserDefaults.standard.set(value, forKey: UserDefaultsKeys.loggedIn.rawValue)
|
||||
setUserKey(with: id)
|
||||
isLoggedIn = UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue)
|
||||
}
|
||||
|
||||
func setUserKey(with id: Int){
|
||||
UserDefaults.standard.set(id, forKey: UserDefaultsKeys.id.rawValue)
|
||||
}
|
||||
|
||||
func getUserId() -> Int {
|
||||
return UserDefaults.standard.integer(forKey: UserDefaultsKeys.id.rawValue)
|
||||
}
|
||||
|
||||
/**
|
||||
Function to determine is user logged in already or not
|
||||
*/
|
||||
func isLoggedIn() -> Bool {
|
||||
return UserDefaults.standard.bool(forKey: UserDefaultsKeys.loggedIn.rawValue)
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,4 +56,5 @@ class DataStorage{
|
||||
*/
|
||||
enum UserDefaultsKeys: String{
|
||||
case loggedIn
|
||||
case id
|
||||
}
|
||||
|
@ -52,7 +52,11 @@ extension UIStoryboard {
|
||||
return UIStoryboard.userEdit.instantiateViewController(withIdentifier: "TabBar") as! UITabBarController
|
||||
}
|
||||
|
||||
class func navChannels() ->UINavigationController{
|
||||
return UIStoryboard.userEdit.instantiateViewController(withIdentifier: "navChannels") as! UINavigationController
|
||||
class func navRoot() -> UINavigationController{
|
||||
return UIStoryboard.userEdit.instantiateViewController(withIdentifier: "root") as! UINavigationController
|
||||
}
|
||||
|
||||
class func makeLogIn() -> LogInViewController {
|
||||
return UIStoryboard.userEdit.instantiateViewController(withIdentifier: logInController) as! LogInViewController
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ class Channel: Equatable {
|
||||
var hashtags: [String] = []
|
||||
var people: [String] = []
|
||||
|
||||
var posts: [Post] = []
|
||||
var posts: [Model.Posts] = []
|
||||
|
||||
init(title: String, subtitle: String, hashtags: [String], people: [String], posts: [Post])
|
||||
init(title: String, subtitle: String = "none", hashtags: [String] = [], people: [String] = [], posts: [Model.Posts])
|
||||
{
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
|
420
GDproject/Simple model/Model.swift
Normal file
420
GDproject/Simple model/Model.swift
Normal file
@ -0,0 +1,420 @@
|
||||
//
|
||||
// Model.swift
|
||||
// GDproject
|
||||
//
|
||||
// Created by cstore on 23/02/2019.
|
||||
// Copyright © 2019 drHSE. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
|
||||
class Model{
|
||||
|
||||
static let invalidTocken = 498
|
||||
|
||||
private static var isValidTocken: ((Int)->())? = { responce in
|
||||
if responce == invalidTocken {
|
||||
DataStorage.standard.setIsLoggedIn(value: false, with: 0)
|
||||
}
|
||||
}
|
||||
|
||||
private static let baseUrl = "https://valera-denis.herokuapp.com"
|
||||
static let decoder = JSONDecoder()
|
||||
|
||||
static let authenticationURL = URL(string:"\(baseUrl)/authentication/login")!
|
||||
static let postsLastURL = URL(string:"\(baseUrl)/posts/last")!
|
||||
static let postsForUserURL = URL(string:"\(baseUrl)/posts/forUser")!
|
||||
static let postsPublishURL = URL(string:"\(baseUrl)/posts/publish")!
|
||||
static let usersURL = URL(string:"\(baseUrl)/users")!
|
||||
static let usersAllURL = URL(string:"\(baseUrl)/users/all")!
|
||||
static let channelsGetURL = URL(string: "\(baseUrl)/channels/get")!
|
||||
static let channelsUpdateURL = URL(string: "\(baseUrl)/channels/update")!
|
||||
static let channelsListURL = URL(string: "\(baseUrl)/channels")!
|
||||
static let channelsCreateURL = URL(string: "\(baseUrl)/channels/create")!
|
||||
static let channelsDeleteURL = URL(string: "\(baseUrl)/channels/delete")!
|
||||
|
||||
|
||||
struct QueryPosts: Codable{
|
||||
var users: [Int: Users]
|
||||
var posts: [Posts]
|
||||
}
|
||||
|
||||
struct Posts: Codable {
|
||||
var body: [Attachments]
|
||||
var authorId: Int
|
||||
var id: Int
|
||||
var user: Model.Users?
|
||||
var updated: String
|
||||
var tags: [String]
|
||||
|
||||
init(body: [Attachments], authorId: Int, id: Int, date: String,tags: [String]) {
|
||||
self.body = body
|
||||
self.authorId = authorId
|
||||
self.id = id
|
||||
self.updated = date
|
||||
self.tags = tags
|
||||
}
|
||||
|
||||
init(body: [Attachments], authorId: Int, id: Int, user: Model.Users, date: String, tags: [String]) {
|
||||
self.body = body
|
||||
self.authorId = authorId
|
||||
self.id = id
|
||||
self.user = user
|
||||
self.updated = date
|
||||
self.tags = tags
|
||||
}
|
||||
|
||||
func convertDateFormatter() -> 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: updated)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
struct CreatedPost: Codable {
|
||||
var body = [Attachments]()
|
||||
var tags = [String]()
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case body
|
||||
case tags
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(body, forKey: .body)
|
||||
try container.encode(tags, forKey: .tags)
|
||||
}
|
||||
}
|
||||
|
||||
struct Users: Codable{
|
||||
|
||||
var middleName: String
|
||||
var lastName: String
|
||||
var firstName: String
|
||||
var id: Int
|
||||
|
||||
}
|
||||
|
||||
struct Attachments: Codable {
|
||||
var markdown: String
|
||||
|
||||
init(markdown: String) {
|
||||
self.markdown = markdown
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case markdown
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(markdown, forKey: .markdown)
|
||||
}
|
||||
}
|
||||
|
||||
struct Channels: Codable {
|
||||
|
||||
static var fullTags = Set<String>()
|
||||
static var fullPeople = [Users]()
|
||||
static var fullPeopleDict = [Int:Users]()
|
||||
|
||||
var people: [Int]
|
||||
var name: String
|
||||
var id: Int?
|
||||
var tags: [String]
|
||||
|
||||
init(people: [Int], name: String, id: Int, tags: [String]) {
|
||||
self.id = id
|
||||
self.people = people
|
||||
self.tags = tags
|
||||
self.name = name
|
||||
}
|
||||
|
||||
init(people: [Int], name: String, tags: [String]) {
|
||||
self.people = people
|
||||
self.tags = tags
|
||||
self.name = name
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case people
|
||||
case name
|
||||
case id
|
||||
case tags
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(people, forKey: .people)
|
||||
try container.encode(name, forKey: .name)
|
||||
try container.encode(id, forKey: .id)
|
||||
try container.encode(tags, forKey: .tags)
|
||||
}
|
||||
}
|
||||
|
||||
static func authenticate(with id: Int, completion: @escaping ((Bool)->())) {
|
||||
|
||||
let json: [String:Any] = ["authenticationId" : id]
|
||||
let jsonData = try? JSONSerialization.data(withJSONObject: json)
|
||||
|
||||
var request = URLRequest(url: authenticationURL)
|
||||
request.httpMethod = "POST"
|
||||
|
||||
// insert json data to the request
|
||||
request.httpBody = jsonData
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
AF.request(request).response { (responce) in
|
||||
|
||||
guard let realResponse = responce.response, realResponse.statusCode == 200 else
|
||||
{
|
||||
print("Not a 200 response")
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
|
||||
guard let json = responce.data else { return }
|
||||
guard let personId = Int(String(data: json, encoding: String.Encoding.utf8)!) else {
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
|
||||
let fields = realResponse.allHeaderFields as? [String :String]
|
||||
|
||||
let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields!, for: realResponse.url!)
|
||||
|
||||
HTTPCookieStorage.shared.setCookie(cookies[0])
|
||||
|
||||
DataStorage.standard.setIsLoggedIn(value: true, with: personId)
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static func getLast(completion: @escaping (((users:[Int: Users], posts:[Posts]))->())){
|
||||
let jsonString = "30"
|
||||
var request = URLRequest(url: postsLastURL)
|
||||
|
||||
request.httpMethod = "POST"
|
||||
|
||||
// insert json data to the request
|
||||
request.httpBody = jsonString.data(using: .utf8)
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
AF.request(request).responseJSON {
|
||||
(response) in
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
|
||||
guard let json = response.data else { return }
|
||||
|
||||
guard let newQueery = try? decoder.decode(QueryPosts.self, from: json) else { print("no")
|
||||
return }
|
||||
|
||||
idUser = newQueery.users
|
||||
completion((newQueery.users, newQueery.posts))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static func createAndPublish(body: [Attachments], tags: [String]){
|
||||
let jsonUpd = CreatedPost(body: body, tags: tags)
|
||||
var request = URLRequest(url: postsPublishURL)
|
||||
|
||||
request.httpMethod = "POST"
|
||||
|
||||
// insert json data to the request
|
||||
request.httpBody = try? JSONEncoder().encode(jsonUpd)
|
||||
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
AF.request(request).response {
|
||||
(response) in
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static func getPostsForUser(with id: Int, completion: @escaping (([Posts])->())){
|
||||
let json = [
|
||||
"request" : id,
|
||||
"limit": 10
|
||||
]
|
||||
|
||||
let jsonData = try? JSONSerialization.data(withJSONObject: json)
|
||||
|
||||
var request = URLRequest(url: postsForUserURL)
|
||||
request.httpMethod = "POST"
|
||||
|
||||
// insert json data to the request
|
||||
request.httpBody = jsonData
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
AF.request(request).responseJSON {
|
||||
(response) in
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
|
||||
guard let json = response.data else { return }
|
||||
|
||||
guard let newPost = try? decoder.decode(QueryPosts.self, from: json) else { return }
|
||||
|
||||
completion(newPost.posts)
|
||||
}
|
||||
}
|
||||
|
||||
static var idUser: [Int:Users] = [:]
|
||||
|
||||
static func getUsers(for ids: [Int], completion: @escaping (([Int:Users])->())){
|
||||
let json = "\(Set(ids))"
|
||||
print(json)
|
||||
var request = URLRequest(url: usersURL)
|
||||
|
||||
request.httpMethod = "POST"
|
||||
|
||||
// insert json data to the request
|
||||
request.httpBody = json.data(using: .utf8)
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
AF.request(request).responseJSON {
|
||||
(response) in
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
|
||||
guard let json = response.data else { return }
|
||||
|
||||
guard let users = try? decoder.decode([Users].self, from: json) else { return }
|
||||
|
||||
var dict: [Int:Users] = [:]
|
||||
users.forEach({ (user) in
|
||||
dict[user.id] = user
|
||||
})
|
||||
|
||||
completion(dict)
|
||||
}
|
||||
}
|
||||
|
||||
// get channel (with id): in responce -- PostQuery
|
||||
static func getChannel(with channelId: Int, completion: @escaping (((users:[Int: Users], posts:[Posts]))->())){
|
||||
let json = [
|
||||
"request" : channelId,
|
||||
"limit": 10
|
||||
]
|
||||
|
||||
let jsonData = try? JSONSerialization.data(withJSONObject: json)
|
||||
|
||||
var request = URLRequest(url: channelsGetURL)
|
||||
request.httpMethod = "POST"
|
||||
|
||||
// insert json data to the request
|
||||
request.httpBody = jsonData
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
AF.request(request).responseJSON {
|
||||
(response) in
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
|
||||
|
||||
guard let json = response.data else { return }
|
||||
|
||||
guard let newQueery = try? decoder.decode(QueryPosts.self, from: json) else { return }
|
||||
|
||||
idUser = newQueery.users
|
||||
completion((newQueery.users, newQueery.posts))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static func createChannel(with channel: Channels) {
|
||||
|
||||
var request = URLRequest(url: channelsCreateURL)
|
||||
request.httpMethod = "POST"
|
||||
request.httpBody = try? JSONEncoder().encode(channel)
|
||||
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
AF.request(request).response {
|
||||
(response) in
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static func channelsList(completion: @escaping (([Channels])->())){
|
||||
var request = URLRequest(url: channelsListURL)
|
||||
request.httpMethod = "POST"
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
AF.request(request).responseJSON { (response) in
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
|
||||
guard let json = response.data else { return }
|
||||
|
||||
guard let channelsList = try? decoder.decode([Channels].self, from: json) else { return }
|
||||
|
||||
completion(channelsList)
|
||||
}
|
||||
}
|
||||
|
||||
static func channelsDelete(by id: Int, completion: @escaping(()->())){
|
||||
var request = URLRequest(url: channelsDeleteURL)
|
||||
request.httpMethod = "POST"
|
||||
request.httpBody = "\(id)".data(using: .utf8)
|
||||
print("\(id)")
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
AF.request(request).response { (response) in
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
}
|
||||
completion()
|
||||
}
|
||||
|
||||
static func updateChannel(with channel: Channels) {
|
||||
|
||||
var request = URLRequest(url: channelsUpdateURL)
|
||||
request.httpMethod = "POST"
|
||||
request.httpBody = try? JSONEncoder().encode(channel)
|
||||
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
AF.request(request).response {
|
||||
(response) in
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
}
|
||||
}
|
||||
|
||||
static func usersAllGet() {
|
||||
var request = URLRequest(url: usersAllURL)
|
||||
request.httpMethod = "POST"
|
||||
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
AF.request(request).response {
|
||||
(response) in
|
||||
guard let json = response.data else { return }
|
||||
|
||||
guard let users = try? decoder.decode([Users].self, from: json) else { return }
|
||||
|
||||
Channels.fullPeople = users
|
||||
Channels.fullPeopleDict = users.reduce([Int: Users]()) { (dict, person) -> [Int: Users] in
|
||||
var dict = dict
|
||||
dict[person.id] = person
|
||||
return dict
|
||||
}
|
||||
|
||||
isValidTocken?(response.response?.statusCode ?? 498)
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,8 @@ import UIKit
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var coordinator: ChannelsCoordinator!
|
||||
|
||||
var coordinator: LogInCoordinator!
|
||||
var tabCoordinator: TabbarCoordinator!
|
||||
|
||||
var window: UIWindow?
|
||||
@ -19,16 +20,25 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
return self.window!.rootViewController as? UINavigationController
|
||||
}
|
||||
|
||||
private func makeCoordinator(with: UINavigationController) -> ChannelsCoordinator {
|
||||
return ChannelsCoordinator(currentChannel: Channel(title: "example", subtitle: "ex", hashtags: ["none"], people: ["none"], posts: []), navigationController: with)
|
||||
func logInAgain(){
|
||||
let root = UIStoryboard.navRoot()
|
||||
window?.rootViewController = root
|
||||
window?.makeKeyAndVisible()
|
||||
coordinator = LogInCoordinator(navigationController: root, window: UIApplication.shared.keyWindow!)
|
||||
coordinator!.start()
|
||||
}
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
|
||||
{
|
||||
|
||||
// TODO:- determine what to do here: log in or tabbar
|
||||
coordinator = LogInCoordinator(navigationController: rootController!, window: window!)
|
||||
tabCoordinator = TabbarCoordinator(window: window!)
|
||||
tabCoordinator.start()
|
||||
// TODO:- determine what to do here: log in or tabbar
|
||||
if DataStorage.standard.isLoggedIn {
|
||||
tabCoordinator.start()
|
||||
} else {
|
||||
coordinator.start()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
BIN
GDproject/Supporting files/Assets.xcassets/1.imageset/1.pdf
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/1.imageset/1.pdf
vendored
Normal file
Binary file not shown.
25
GDproject/Supporting files/Assets.xcassets/1.imageset/Contents.json
vendored
Normal file
25
GDproject/Supporting files/Assets.xcassets/1.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "1.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template",
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/2.imageset/2.pdf
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/2.imageset/2.pdf
vendored
Normal file
Binary file not shown.
21
GDproject/Supporting files/Assets.xcassets/2.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/2.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "2.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/3.imageset/3.pdf
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/3.imageset/3.pdf
vendored
Normal file
Binary file not shown.
21
GDproject/Supporting files/Assets.xcassets/3.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/3.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "3.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/4.imageset/4.pdf
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/4.imageset/4.pdf
vendored
Normal file
Binary file not shown.
21
GDproject/Supporting files/Assets.xcassets/4.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/4.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "4.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/42.imageset/42.png
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/42.imageset/42.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
21
GDproject/Supporting files/Assets.xcassets/42.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/42.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "42.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/5.imageset/5.pdf
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/5.imageset/5.pdf
vendored
Normal file
Binary file not shown.
21
GDproject/Supporting files/Assets.xcassets/5.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/5.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "5.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/5051.imageset/5051.png
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/5051.imageset/5051.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
21
GDproject/Supporting files/Assets.xcassets/5051.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/5051.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "5051.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/69.imageset/69.png
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/69.imageset/69.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
21
GDproject/Supporting files/Assets.xcassets/69.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/69.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "69.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/9.imageset/9.png
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/9.imageset/9.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
21
GDproject/Supporting files/Assets.xcassets/9.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/9.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "9.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
21
GDproject/Supporting files/Assets.xcassets/share.imageset/Contents.json
vendored
Normal file
21
GDproject/Supporting files/Assets.xcassets/share.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "share.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
GDproject/Supporting files/Assets.xcassets/share.imageset/share.png
vendored
Normal file
BIN
GDproject/Supporting files/Assets.xcassets/share.imageset/share.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Loading…
Reference in New Issue
Block a user