Merge pull request #12 from dashared/developer

version 3: channels
This commit is contained in:
Darya Rednikina 2019-03-15 23:18:51 +03:00 committed by GitHub
commit 1aeab21fec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1709 additions and 256 deletions

View File

@ -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"

View File

@ -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 */,

View 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>

View File

@ -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>

View File

@ -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"

View File

@ -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()
}

View File

@ -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])
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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(){

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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) {

View 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)
}
}

View File

@ -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
}
})
}
}

View File

@ -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
}
}

View File

@ -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

View 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()
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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

View 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)
}
}
}

View File

@ -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
}

Binary file not shown.

View 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
}
}

Binary file not shown.

View 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"
}
}

Binary file not shown.

View 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"
}
}

Binary file not shown.

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View 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"
}
}

Binary file not shown.

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View 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"
}
}

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB