git.iko.soy/dashared/GDproject
on master help sign in
post upload availiable, gradient and design of the cells are left
commitf7fc725ebda32fb3a62588820d134680954b05a0 authorDarya Rednikina <rednikina.com@yandex.ru> dateWed 13 Feb 2019, 18:15 (8 years ago) parentd6798a7
15 files changed+791−31
GDproject.xcodeproj/project.pbxproj+103−7 GDproject/Base.lproj/Main.storyboard+74−4 GDproject/Constants.swift+12 GDproject/Controller/ChannelsController.swift+15 GDproject/Controller/HeaderNewsChannels.swift+56 GDproject/Controller/NewPostViewController.swift+257 GDproject/Controller/NewsController.swift+107 GDproject/Controller/PostViewCell.swift+97 GDproject/Simple model/Post.swift+30 GDproject/Simple model/User.swift+40 GDproject/AppDelegate.swift → GDproject/Supporting files/AppDelegate.swift GDproject/Assets.xcassets/AppIcon.appiconset/Contents.json → GDproject/Supporting files/Assets.xcassets/AppIcon.appiconset/Contents.json GDproject/Assets.xcassets/Contents.json → GDproject/Supporting files/Assets.xcassets/Contents.json GDproject/Base.lproj/LaunchScreen.storyboard → GDproject/Supporting files/Base.lproj/LaunchScreen.storyboard GDproject/ViewController.swift−20
GDproject.xcodeproj/project.pbxproj+103−7
@@ -8,20 +8,62 @@
88
99/* Begin PBXBuildFile section */
1010 12E36D9C221424EA006FCDD7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36D9B221424EA006FCDD7 /* AppDelegate.swift */; };
11− 12E36D9E221424EA006FCDD7 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36D9D221424EA006FCDD7 /* ViewController.swift */; };
11+ 12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36D9D221424EA006FCDD7 /* NewsController.swift */; };
1212 12E36DA1221424EA006FCDD7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36D9F221424EA006FCDD7 /* Main.storyboard */; };
1313 12E36DA3221424ED006FCDD7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA2221424ED006FCDD7 /* Assets.xcassets */; };
1414 12E36DA6221424ED006FCDD7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 12E36DA4221424ED006FCDD7 /* LaunchScreen.storyboard */; };
15+ 12E36DAF22143D40006FCDD7 /* Cartography.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DAE22143D40006FCDD7 /* Cartography.framework */; };
16+ 12E36DB322143D4E006FCDD7 /* Marklight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB222143D4E006FCDD7 /* Marklight.framework */; };
17+ 12E36DB522143D54006FCDD7 /* TinyConstraints.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */; };
18+ 12E36DB72214400A006FCDD7 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB62214400A006FCDD7 /* Post.swift */; };
19+ 12E36DB922144016006FCDD7 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DB822144016006FCDD7 /* User.swift */; };
20+ 12E36DBD221441D5006FCDD7 /* TinyConstraints.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
21+ 12E36DC0221441DB006FCDD7 /* Marklight.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB222143D4E006FCDD7 /* Marklight.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
22+ 12E36DC2221441E1006FCDD7 /* MarkdownKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
23+ 12E36DC4221441EA006FCDD7 /* Cartography.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 12E36DAE22143D40006FCDD7 /* Cartography.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
24+ 12E36DC622144266006FCDD7 /* HeaderNewsChannels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DC522144266006FCDD7 /* HeaderNewsChannels.swift */; };
25+ 12E36DC822144374006FCDD7 /* ChannelsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DC722144374006FCDD7 /* ChannelsController.swift */; };
26+ 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DC922144635006FCDD7 /* NewPostViewController.swift */; };
27+ 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCB22144725006FCDD7 /* PostViewCell.swift */; };
28+ 12E36DCE22144756006FCDD7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E36DCD22144756006FCDD7 /* Constants.swift */; };
1529/* End PBXBuildFile section */
1630
31+/* Begin PBXCopyFilesBuildPhase section */
32+ 12E36DBE221441D5006FCDD7 /* Embed Frameworks */ = {
33+ isa = PBXCopyFilesBuildPhase;
34+ buildActionMask = 2147483647;
35+ dstPath = "";
36+ dstSubfolderSpec = 10;
37+ files = (
38+ 12E36DC0221441DB006FCDD7 /* Marklight.framework in Embed Frameworks */,
39+ 12E36DC4221441EA006FCDD7 /* Cartography.framework in Embed Frameworks */,
40+ 12E36DBD221441D5006FCDD7 /* TinyConstraints.framework in Embed Frameworks */,
41+ 12E36DC2221441E1006FCDD7 /* MarkdownKit.framework in Embed Frameworks */,
42+ );
43+ name = "Embed Frameworks";
44+ runOnlyForDeploymentPostprocessing = 0;
45+ };
46+/* End PBXCopyFilesBuildPhase section */
47+
1748/* Begin PBXFileReference section */
1849 12E36D98221424EA006FCDD7 /* GDproject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GDproject.app; sourceTree = BUILT_PRODUCTS_DIR; };
1950 12E36D9B221424EA006FCDD7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
20− 12E36D9D221424EA006FCDD7 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
51+ 12E36D9D221424EA006FCDD7 /* NewsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsController.swift; sourceTree = "<group>"; };
2152 12E36DA0221424EA006FCDD7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
2253 12E36DA2221424ED006FCDD7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
2354 12E36DA5221424ED006FCDD7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
2455 12E36DA7221424ED006FCDD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
56+ 12E36DAE22143D40006FCDD7 /* Cartography.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cartography.framework; path = Carthage/Build/iOS/Cartography.framework; sourceTree = "<group>"; };
57+ 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MarkdownKit.framework; path = Carthage/Build/iOS/MarkdownKit.framework; sourceTree = "<group>"; };
58+ 12E36DB222143D4E006FCDD7 /* Marklight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Marklight.framework; path = Carthage/Build/iOS/Marklight.framework; sourceTree = "<group>"; };
59+ 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TinyConstraints.framework; path = Carthage/Build/iOS/TinyConstraints.framework; sourceTree = "<group>"; };
60+ 12E36DB62214400A006FCDD7 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
61+ 12E36DB822144016006FCDD7 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
62+ 12E36DC522144266006FCDD7 /* HeaderNewsChannels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderNewsChannels.swift; sourceTree = "<group>"; };
63+ 12E36DC722144374006FCDD7 /* ChannelsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelsController.swift; sourceTree = "<group>"; };
64+ 12E36DC922144635006FCDD7 /* NewPostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPostViewController.swift; sourceTree = "<group>"; };
65+ 12E36DCB22144725006FCDD7 /* PostViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewCell.swift; sourceTree = "<group>"; };
66+ 12E36DCD22144756006FCDD7 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
2567/* End PBXFileReference section */
2668
2769/* Begin PBXFrameworksBuildPhase section */
@@ -29,6 +71,9 @@
2971 isa = PBXFrameworksBuildPhase;
3072 buildActionMask = 2147483647;
3173 files = (
74+ 12E36DB522143D54006FCDD7 /* TinyConstraints.framework in Frameworks */,
75+ 12E36DAF22143D40006FCDD7 /* Cartography.framework in Frameworks */,
76+ 12E36DB322143D4E006FCDD7 /* Marklight.framework in Frameworks */,
3277 );
3378 runOnlyForDeploymentPostprocessing = 0;
3479 };
@@ -38,6 +83,10 @@
3883 12E36D8F221424EA006FCDD7 = {
3984 isa = PBXGroup;
4085 children = (
86+ 12E36DB422143D54006FCDD7 /* TinyConstraints.framework */,
87+ 12E36DB222143D4E006FCDD7 /* Marklight.framework */,
88+ 12E36DB022143D47006FCDD7 /* MarkdownKit.framework */,
89+ 12E36DAE22143D40006FCDD7 /* Cartography.framework */,
4190 12E36D9A221424EA006FCDD7 /* GDproject */,
4291 12E36D99221424EA006FCDD7 /* Products */,
4392 );
@@ -54,16 +103,47 @@
54103 12E36D9A221424EA006FCDD7 /* GDproject */ = {
55104 isa = PBXGroup;
56105 children = (
57− 12E36D9B221424EA006FCDD7 /* AppDelegate.swift */,
58− 12E36D9D221424EA006FCDD7 /* ViewController.swift */,
106+ 12E36DCF22145923006FCDD7 /* Controller */,
107+ 12E36DCD22144756006FCDD7 /* Constants.swift */,
108+ 12E36DBB2214402B006FCDD7 /* Supporting files */,
109+ 12E36DBA2214401B006FCDD7 /* Simple model */,
59110 12E36D9F221424EA006FCDD7 /* Main.storyboard */,
60− 12E36DA2221424ED006FCDD7 /* Assets.xcassets */,
61− 12E36DA4221424ED006FCDD7 /* LaunchScreen.storyboard */,
62111 12E36DA7221424ED006FCDD7 /* Info.plist */,
63112 );
64113 path = GDproject;
65114 sourceTree = "<group>";
66115 };
116+ 12E36DBA2214401B006FCDD7 /* Simple model */ = {
117+ isa = PBXGroup;
118+ children = (
119+ 12E36DB62214400A006FCDD7 /* Post.swift */,
120+ 12E36DB822144016006FCDD7 /* User.swift */,
121+ );
122+ path = "Simple model";
123+ sourceTree = "<group>";
124+ };
125+ 12E36DBB2214402B006FCDD7 /* Supporting files */ = {
126+ isa = PBXGroup;
127+ children = (
128+ 12E36D9B221424EA006FCDD7 /* AppDelegate.swift */,
129+ 12E36DA2221424ED006FCDD7 /* Assets.xcassets */,
130+ 12E36DA4221424ED006FCDD7 /* LaunchScreen.storyboard */,
131+ );
132+ path = "Supporting files";
133+ sourceTree = "<group>";
134+ };
135+ 12E36DCF22145923006FCDD7 /* Controller */ = {
136+ isa = PBXGroup;
137+ children = (
138+ 12E36DC522144266006FCDD7 /* HeaderNewsChannels.swift */,
139+ 12E36DC722144374006FCDD7 /* ChannelsController.swift */,
140+ 12E36D9D221424EA006FCDD7 /* NewsController.swift */,
141+ 12E36DCB22144725006FCDD7 /* PostViewCell.swift */,
142+ 12E36DC922144635006FCDD7 /* NewPostViewController.swift */,
143+ );
144+ path = Controller;
145+ sourceTree = "<group>";
146+ };
67147/* End PBXGroup section */
68148
69149/* Begin PBXNativeTarget section */
@@ -74,6 +154,7 @@
74154 12E36D94221424EA006FCDD7 /* Sources */,
75155 12E36D95221424EA006FCDD7 /* Frameworks */,
76156 12E36D96221424EA006FCDD7 /* Resources */,
157+ 12E36DBE221441D5006FCDD7 /* Embed Frameworks */,
77158 );
78159 buildRules = (
79160 );
@@ -135,8 +216,15 @@
135216 isa = PBXSourcesBuildPhase;
136217 buildActionMask = 2147483647;
137218 files = (
138− 12E36D9E221424EA006FCDD7 /* ViewController.swift in Sources */,
219+ 12E36DC822144374006FCDD7 /* ChannelsController.swift in Sources */,
220+ 12E36DB922144016006FCDD7 /* User.swift in Sources */,
221+ 12E36DB72214400A006FCDD7 /* Post.swift in Sources */,
222+ 12E36DCA22144635006FCDD7 /* NewPostViewController.swift in Sources */,
223+ 12E36D9E221424EA006FCDD7 /* NewsController.swift in Sources */,
224+ 12E36DC622144266006FCDD7 /* HeaderNewsChannels.swift in Sources */,
225+ 12E36DCC22144725006FCDD7 /* PostViewCell.swift in Sources */,
139226 12E36D9C221424EA006FCDD7 /* AppDelegate.swift in Sources */,
227+ 12E36DCE22144756006FCDD7 /* Constants.swift in Sources */,
140228 );
141229 runOnlyForDeploymentPostprocessing = 0;
142230 };
@@ -284,6 +372,10 @@
284372 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
285373 CODE_SIGN_STYLE = Automatic;
286374 DEVELOPMENT_TEAM = 9Z6LFGKA9G;
375+ FRAMEWORK_SEARCH_PATHS = (
376+ "$(inherited)",
377+ "$(PROJECT_DIR)/Carthage/Build/iOS",
378+ );
287379 INFOPLIST_FILE = GDproject/Info.plist;
288380 LD_RUNPATH_SEARCH_PATHS = (
289381 "$(inherited)",
@@ -302,6 +394,10 @@
302394 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
303395 CODE_SIGN_STYLE = Automatic;
304396 DEVELOPMENT_TEAM = 9Z6LFGKA9G;
397+ FRAMEWORK_SEARCH_PATHS = (
398+ "$(inherited)",
399+ "$(PROJECT_DIR)/Carthage/Build/iOS",
400+ );
305401 INFOPLIST_FILE = GDproject/Info.plist;
306402 LD_RUNPATH_SEARCH_PATHS = (
307403 "$(inherited)",
GDproject/Base.lproj/Main.storyboard+74−4
@@ -1,24 +1,94 @@
11<?xml version="1.0" encoding="UTF-8"?>
2−<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
2+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="NuV-ZG-ld2">
3+ <device id="retina4_7" orientation="portrait">
4+ <adaptation id="fullscreen"/>
5+ </device>
36 <dependencies>
4− <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
7+ <deployment identifier="iOS"/>
8+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
59 <capability name="Safe area layout guides" minToolsVersion="9.0"/>
610 <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
711 </dependencies>
812 <scenes>
9− <!--View Controller-->
13+ <!--News Controller-->
1014 <scene sceneID="tne-QT-ifu">
1115 <objects>
12− <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
16+ <viewController id="BYZ-38-t0r" customClass="NewsController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
1317 <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
1418 <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
1519 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
20+ <subviews>
21+ <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="bdn-EE-6KU">
22+ <rect key="frame" x="0.0" y="116" width="375" height="551"/>
23+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
24+ </tableView>
25+ </subviews>
1626 <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
27+ <constraints>
28+ <constraint firstItem="bdn-EE-6KU" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="Mwc-qc-ZfA"/>
29+ <constraint firstItem="bdn-EE-6KU" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="dww-F7-g9y"/>
30+ <constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="bdn-EE-6KU" secondAttribute="trailing" id="wlT-ZO-QGd"/>
31+ <constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="bdn-EE-6KU" secondAttribute="bottom" id="yXX-zW-vb8"/>
32+ </constraints>
1733 <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
1834 </view>
35+ <navigationItem key="navigationItem" largeTitleDisplayMode="always" id="caN-kg-RZ4"/>
36+ <connections>
37+ <outlet property="tableView" destination="bdn-EE-6KU" id="O4Z-at-Hzw"/>
38+ </connections>
1939 </viewController>
2040 <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
2141 </objects>
42+ <point key="canvasLocation" x="1076" y="132.68365817091455"/>
43+ </scene>
44+ <!--New Post View Controller-->
45+ <scene sceneID="TVK-xu-UdJ">
46+ <objects>
47+ <viewController storyboardIdentifier="NewPostViewController" id="uED-wX-77j" customClass="NewPostViewController" customModule="GDproject" customModuleProvider="target" sceneMemberID="viewController">
48+ <view key="view" contentMode="scaleToFill" id="6UN-Bs-PPg">
49+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
50+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
51+ <subviews>
52+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sSz-uJ-A7n">
53+ <rect key="frame" x="0.0" y="20" width="375" height="647"/>
54+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
55+ </view>
56+ </subviews>
57+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
58+ <constraints>
59+ <constraint firstItem="sSz-uJ-A7n" firstAttribute="leading" secondItem="wxD-Ek-mgv" secondAttribute="leading" id="2J7-Bi-PzG"/>
60+ <constraint firstItem="wxD-Ek-mgv" firstAttribute="trailing" secondItem="sSz-uJ-A7n" secondAttribute="trailing" id="HrU-bs-qsE"/>
61+ <constraint firstItem="wxD-Ek-mgv" firstAttribute="bottom" secondItem="sSz-uJ-A7n" secondAttribute="bottom" id="oZ7-xQ-9Cb"/>
62+ <constraint firstItem="sSz-uJ-A7n" firstAttribute="top" secondItem="wxD-Ek-mgv" secondAttribute="top" id="zuN-mZ-hgU"/>
63+ </constraints>
64+ <viewLayoutGuide key="safeArea" id="wxD-Ek-mgv"/>
65+ </view>
66+ <connections>
67+ <outlet property="bottomTextViewConstraint" destination="oZ7-xQ-9Cb" id="6In-71-0TX"/>
68+ <outlet property="view1" destination="sSz-uJ-A7n" id="5nX-oT-kUi"/>
69+ </connections>
70+ </viewController>
71+ <placeholder placeholderIdentifier="IBFirstResponder" id="3fd-7N-vPg" userLabel="First Responder" sceneMemberID="firstResponder"/>
72+ </objects>
73+ <point key="canvasLocation" x="1773" y="132"/>
74+ </scene>
75+ <!--Navigation Controller-->
76+ <scene sceneID="RSd-UJ-34B">
77+ <objects>
78+ <navigationController automaticallyAdjustsScrollViewInsets="NO" id="NuV-ZG-ld2" sceneMemberID="viewController">
79+ <toolbarItems/>
80+ <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" largeTitles="YES" id="6qB-3A-tuL">
81+ <rect key="frame" x="0.0" y="20" width="375" height="96"/>
82+ <autoresizingMask key="autoresizingMask"/>
83+ </navigationBar>
84+ <nil name="viewControllers"/>
85+ <connections>
86+ <segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="ehh-1b-ZGK"/>
87+ </connections>
88+ </navigationController>
89+ <placeholder placeholderIdentifier="IBFirstResponder" id="POV-5T-jeQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
90+ </objects>
91+ <point key="canvasLocation" x="150" y="133"/>
2292 </scene>
2393 </scenes>
2494</document>
GDproject/Constants.swiftnew file+12
@@ -0,0 +1,12 @@
1+//
2+// Constants.swift
3+// GDproject
4+//
5+// Created by cstore on 13/02/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+//constant for cell in posts NewsController.swift
10+let postCellId = "PostCell"
11+// constant for segmented controll in NewsController.swift and ChannelsController.swift
12+let headerNewsChannelsVC = "HeaderSegmentedControll"
GDproject/Controller/ChannelsController.swiftnew file+15
@@ -0,0 +1,15 @@
1+//
2+// PostTable.swift
3+// GDproject
4+//
5+// Created by cstore on 13/02/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+
11+class ChannelsController: UITableViewController {
12+
13+
14+
15+}
GDproject/Controller/HeaderNewsChannels.swiftnew file+56
@@ -0,0 +1,56 @@
1+//
2+// HeaderNewsChannels.swift
3+// GDproject
4+//
5+// Created by cstore on 13/02/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+import TinyConstraints
11+
12+class HeaderNewsChannels: UITableViewCell {
13+
14+ weak var tableView: UITableView?
15+ weak var vc: NewsController?
16+
17+ let basicInfo = ChannelsController()
18+
19+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
20+ super.init(style: style, reuseIdentifier: reuseIdentifier)
21+ backgroundColor = .white
22+ setUpCell()
23+ }
24+
25+ required init?(coder aDecoder: NSCoder) {
26+ super.init(coder: aDecoder)
27+ }
28+
29+ func setUpCell(){
30+ addSubview(postsChannelsSegment)
31+ postsChannelsSegment.selectedSegmentIndex = 0
32+ postsChannelsSegment.addTarget(self, action: #selector(changedValue), for: .valueChanged)
33+ postsChannelsSegment.edgesToSuperview(insets: .left(16) + .right(16) + .top(8) + .bottom(8))
34+ }
35+
36+ // Initialize
37+ let postsChannelsSegment = UISegmentedControl(items: ["Posts", "Channels"])
38+
39+ @objc func changedValue(_ sender: UISegmentedControl) {
40+ let index = sender.selectedSegmentIndex
41+ switch index {
42+ case 0:
43+ print("posts")
44+ vc?.setUpNavigationItemsforPosts()
45+ case 1:
46+ print("channels")
47+ vc?.setUpNavigationItemsForChannels()
48+// self.tableView?.delegate = basicInfo
49+// self.tableView?.dataSource = basicInfo
50+// tableView?.reloadData()
51+ default:
52+ break
53+ }
54+ }
55+}
56+
GDproject/Controller/NewPostViewController.swiftnew file+257
@@ -0,0 +1,257 @@
1+//
2+// NewPostViewController.swift
3+// GDproject
4+//
5+// Created by cstore on 05/02/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+import Cartography
11+import Marklight
12+import TinyConstraints
13+
14+class NewPostViewController: UIViewController, UITextViewDelegate {
15+
16+ @IBOutlet weak var view1: UIView!
17+ // Keep strong instance of the `NSTextStorage` subclass
18+ let textStorage = MarklightTextStorage()
19+
20+ weak var parentVC: NewsController?
21+
22+ static var draft: String = ""
23+ var textView: UITextView!
24+
25+ // buttons for attaching images
26+ var accessoryView: UIView = {
27+ let view = UIView()
28+ view.backgroundColor = .white
29+ return view
30+ }()
31+
32+ var addEquasion: UIButton = {
33+ var button = UIButton(type: .detailDisclosure)
34+ button.addTarget(self, action: #selector(addMathBrackets), for: .touchUpInside)
35+ return button
36+ }()
37+
38+ // stack view where buttons will be places
39+ var stackAccessoryView: UIStackView?
40+ // Connect the view1's bottom layout constraint to react to keyboard movements
41+
42+ @IBOutlet weak var bottomTextViewConstraint: NSLayoutConstraint!
43+
44+
45+ override func viewDidLoad()
46+ {
47+ super.viewDidLoad()
48+ setUpMD()
49+ setUpTextView()
50+ setUpAccessoryView()
51+ }
52+
53+ override func viewWillAppear(_ animated: Bool) {
54+ super.viewWillAppear(animated)
55+
56+ navigationController?.navigationBar.prefersLargeTitles = false
57+ navigationItem.title = "New post"
58+ textView.text = NewPostViewController.draft
59+ }
60+
61+ func setUpAccessoryView(){
62+ let views = [UIButton(type: .contactAdd),addEquasion]
63+ stackAccessoryView = UIStackView(arrangedSubviews: views)
64+
65+ stackAccessoryView?.alignment = .fill
66+ stackAccessoryView?.distribution = .equalSpacing
67+
68+ view1.addSubview(accessoryView)
69+ accessoryView.addSubview(stackAccessoryView!)
70+ accessoryView.height(40)
71+
72+ let separatorView = UIView()
73+ separatorView.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
74+ accessoryView.addSubview(separatorView)
75+ separatorView.height(1)
76+ separatorView.edgesToSuperview(excluding: .bottom)
77+
78+ accessoryView.edgesToSuperview(excluding: [.top])
79+ stackAccessoryView!.edgesToSuperview(insets: .left(16) + .right(16) + .top(1))
80+ }
81+
82+ func setUpTextView(){
83+ view.addConstraint(bottomTextViewConstraint)
84+ view1.addSubview(textView)
85+ textView.edgesToSuperview(insets: .top(8) + .left(8) + .bottom(40+8) + .right(8))
86+
87+ if #available(iOS 11.0, *) {
88+ textView.smartDashesType = .no
89+ textView.smartQuotesType = .no
90+ }
91+
92+ textView.isScrollEnabled = true
93+
94+ guard let bottomTextViewConstraint = bottomTextViewConstraint else { return }
95+ view.addConstraint(bottomTextViewConstraint)
96+
97+ // Add a beautiful padding to the `UITextView` content
98+ textView.textContainerInset = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4)
99+ textView.delegate = self
100+ magicForKeyboardChanges()
101+ }
102+
103+
104+ func magicForKeyboardChanges()
105+ {
106+ /////////////////////////////
107+ // We do some magic to resize the `UITextView` to react the the keyboard size change (appearance, disappearance, ecc)
108+ NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillShowNotification, object: nil)
109+
110+ NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotifications), name: UIResponder.keyboardWillHideNotification, object: nil)
111+
112+ // Partial fixes to a long standing bug, to keep the caret inside the `UITextView` always visible
113+ NotificationCenter.default.addObserver(forName: UITextView.textDidChangeNotification, object: textView, queue: OperationQueue.main) { (notification) -> Void in
114+ if self.textView.textStorage.string.hasSuffix("\n") {
115+ CATransaction.setCompletionBlock({ () -> Void in
116+ self.scrollToCaret(self.textView, animated: false)
117+ })
118+ } else {
119+ self.scrollToCaret(self.textView, animated: false)
120+ }
121+ }
122+
123+ }
124+
125+ @objc func handleKeyboardNotifications(notification: NSNotification){
126+ if let userInfo = notification.userInfo{
127+ // UIKeyboardFrameEndUserInfoKey
128+ let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
129+ bottomTextViewConstraint?.constant = notification.name == UIResponder.keyboardWillShowNotification ? keyBoardFrame.height : 0
130+ print(bottomTextViewConstraint!.constant)
131+
132+ UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
133+ self.view.layoutIfNeeded()
134+ }) { (completed) in
135+
136+ }
137+ }
138+ }
139+
140+ @objc func attachPhoto(){
141+
142+ }
143+
144+
145+ @objc func addMathBrackets()
146+ {
147+ if textView.text.count != 0 && textView.text.last != "\n" {
148+ textView.insertText("\n\\[\n ")
149+ }
150+ else {
151+ textView.insertText("\\[\n ")
152+ }
153+
154+ if let selectedRange = textView.selectedTextRange
155+ {
156+ textView.insertText("\n\\]\n")
157+
158+ if let newPosition = textView.position(from: selectedRange.start, offset: 0)
159+ {
160+ // set the new position
161+ textView.selectedTextRange = textView.textRange(from: newPosition, to: newPosition)
162+ }
163+ }
164+ }
165+
166+ func setUpMD(){
167+ textStorage.marklightTextProcessor.codeColor = UIColor.orange
168+ textStorage.marklightTextProcessor.quoteColor = UIColor.darkGray
169+ textStorage.marklightTextProcessor.syntaxColor = UIColor.blue
170+ textStorage.marklightTextProcessor.codeFontName = "Courier"
171+ textStorage.marklightTextProcessor.fontTextStyle = UIFont.TextStyle.subheadline.rawValue
172+ textStorage.marklightTextProcessor.hideSyntax = false
173+
174+ let layoutManager = NSLayoutManager()
175+
176+ // Assign the `UITextView`'s `NSLayoutManager` to the `NSTextStorage` subclass
177+ textStorage.addLayoutManager(layoutManager)
178+
179+ let textContainer = NSTextContainer()
180+ layoutManager.addTextContainer(textContainer)
181+
182+ textView = UITextView(frame: view.bounds, textContainer: textContainer)
183+ }
184+
185+ // MARK:- new post
186+ @objc func newPost(){
187+ let p = Post(dataArray: [.text(textView.text)], from: User(name: "Сева", id: 5, fullName: "Сева Леонидович"), date: "12.01.19")
188+
189+
190+ // adding row to uiTableView after adding new post
191+ guard let vc = parentVC else {return}
192+ vc.tableView.beginUpdates()
193+ let indexPath1: IndexPath = IndexPath(row: 0, section: 0)
194+ vc.dataSourse.insert(p, at: 0)
195+ vc.tableView.insertRows(at: [indexPath1], with: .fade)
196+ vc.tableView.endUpdates()
197+ moveBackToParentVC()
198+ // somewhere here i will be sending server notifications about new post arrival
199+ }
200+
201+ @objc func actionSaveDraft(){
202+ let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
203+
204+ let saveAction = UIAlertAction(title: "Save draft", style: .default)
205+ {
206+ _ in
207+ NewPostViewController.draft = self.textView.text
208+ self.moveBackToParentVC()
209+ }
210+
211+ let deleteAction = UIAlertAction(title: "Delete draft", style: .destructive)
212+ {
213+ (_)
214+ in
215+ NewPostViewController.draft = ""
216+ self.moveBackToParentVC()
217+ }
218+
219+ let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
220+
221+ optionMenu.addAction(saveAction)
222+ optionMenu.addAction(deleteAction)
223+ optionMenu.addAction(cancelAction)
224+
225+ self.present(optionMenu, animated: true, completion: nil)
226+ }
227+
228+ @objc func closeView()
229+ {
230+ actionSaveDraft()
231+ }
232+
233+ func moveBackToParentVC(){
234+ let transition = CATransition()
235+ transition.duration = 0.5
236+ transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
237+ transition.type = CATransitionType.reveal
238+ transition.subtype = CATransitionSubtype.fromBottom
239+ navigationController?.view.layer.add(transition, forKey: nil)
240+ navigationController?.popViewController(animated: false)
241+ textView!.resignFirstResponder()
242+ }
243+
244+
245+
246+
247+ func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
248+ print("Should interact with: \(URL)")
249+ return true
250+ }
251+
252+ func scrollToCaret(_ textView: UITextView, animated: Bool) {
253+ var rect = textView.caretRect(for: textView.selectedTextRange!.end)
254+ rect.size.height = rect.size.height + textView.textContainerInset.bottom
255+ textView.scrollRectToVisible(rect, animated: animated)
256+ }
257+}
GDproject/Controller/NewsController.swiftnew file+107
@@ -0,0 +1,107 @@
1+//
2+// ViewController.swift
3+// GDproject
4+//
5+// Created by cstore on 13/02/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+
11+// MARK:- Controller with posts and channels availiable.
12+// Search is availiable within every table (posts and channels). Has button-functionality for boths post and chnnels
13+class NewsController: UIViewController
14+{
15+
16+ @IBOutlet weak var tableView: UITableView!
17+
18+ var dataSourse: [Post] = []
19+
20+ override func viewDidLoad()
21+ {
22+ super.viewDidLoad()
23+ tableView.register(HeaderNewsChannels.self, forCellReuseIdentifier: headerNewsChannelsVC)
24+ tableView.register(PostViewCell.self, forCellReuseIdentifier: postCellId)
25+
26+ tableView.delegate = self
27+ tableView.dataSource = self
28+ tableView.reloadData()
29+
30+ setUpNavigationItemsforPosts()
31+ }
32+
33+ override func viewWillAppear(_ animated: Bool) {
34+ super.viewWillAppear(animated)
35+ navigationController?.navigationBar.prefersLargeTitles = true
36+ }
37+ func setUpNavigationItemsforPosts(){
38+ navigationItem.title = "Posts"
39+ navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(self.writePost(_:)))]
40+ }
41+
42+ func setUpNavigationItemsForChannels(){
43+ navigationItem.title = "Channels"
44+ navigationItem.rightBarButtonItems = [UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addChannel))]
45+ }
46+
47+ @objc func writePost(_ barItem: UIBarButtonItem)
48+ {
49+ let vc = storyboard?.instantiateViewController(withIdentifier: "NewPostViewController") as! NewPostViewController
50+
51+ vc.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Post", style: .plain, target: vc, action: #selector(vc.newPost))
52+ vc.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: vc, action: #selector(vc.closeView))
53+
54+ vc.parentVC = self
55+
56+ let transition = CATransition()
57+ transition.duration = 0.5
58+ transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
59+ transition.type = CATransitionType.moveIn
60+ transition.subtype = CATransitionSubtype.fromTop
61+ navigationController?.view.layer.add(transition, forKey: nil)
62+ navigationController?.pushViewController(vc, animated: false)
63+ }
64+
65+ @objc func addChannel(){
66+ print("Add channel")
67+ }
68+}
69+
70+// MARK:- tableView delegate
71+extension NewsController: UITableViewDelegate{
72+
73+}
74+
75+// MARK:- tableView dataSourse
76+extension NewsController: UITableViewDataSource
77+{
78+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
79+ return dataSourse.count
80+ }
81+
82+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
83+ let cell = tableView.dequeueReusableCell(withIdentifier: postCellId, for: indexPath) as! PostViewCell
84+
85+ cell.fill(with: dataSourse[indexPath.row].dataArray)
86+ return cell
87+ }
88+
89+ func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
90+ return UITableView.automaticDimension
91+ }
92+
93+ func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
94+ return 100.0
95+ }
96+
97+ func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
98+ return 46.0
99+ }
100+
101+ func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
102+ {
103+ let view = tableView.dequeueReusableCell(withIdentifier: headerNewsChannelsVC) as! HeaderNewsChannels
104+ view.vc = self
105+ return view
106+ }
107+}
GDproject/Controller/PostViewCell.swiftnew file+97
@@ -0,0 +1,97 @@
1+//
2+// PostViewCell.swift
3+// GDproject
4+//
5+// Created by cstore on 04/02/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import UIKit
10+import Cartography
11+import MarkdownKit
12+import TinyConstraints
13+
14+class PostViewCell: UITableViewCell
15+{
16+ let nameLabel: UILabel = {
17+ let label = UILabel()
18+ label.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
19+ label.text = "vgogomazova"
20+ label.font = UIFont.boldSystemFont(ofSize: 16)
21+ return label
22+ }()
23+
24+ let fullNameLabel: UILabel = {
25+ let label = UILabel()
26+ label.textColor = #colorLiteral(red: 0.3333333433, green: 0.3333333433, blue: 0.3333333433, alpha: 1)
27+ label.text = "Богомазова Вероника Львовна"
28+ label.font = UIFont.systemFont(ofSize: 12)
29+ return label
30+ }()
31+
32+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
33+ {
34+ super.init(style: style, reuseIdentifier: reuseIdentifier)
35+ }
36+
37+ required init?(coder aDecoder: NSCoder)
38+ {
39+ fatalError("init(coder:) has not been implemented")
40+ }
41+
42+ func createTextView(with text: String) -> UITextView
43+ {
44+ let markdownParser = MarkdownParser(font: UIFont.systemFont(ofSize: 16))
45+ let markdown = text
46+ markdownParser.enabledElements = .disabledAutomaticLink
47+ markdownParser.header.fontIncrease = 6
48+ markdownParser.code.textBackgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
49+
50+ let textView = UITextView()
51+ textView.isScrollEnabled = false
52+ textView.isEditable = false
53+ textView.isUserInteractionEnabled = false
54+ textView.attributedText = markdownParser.parse(markdown)
55+ return textView
56+ }
57+
58+ var views: [UIView] = []
59+ var data : [UIImage] = []
60+
61+ func fill(with info: [Media])
62+ {
63+ // important
64+ contentView.subviews.forEach({ $0.removeFromSuperview() })
65+
66+ data = []
67+ views = []
68+ for item in info.enumerated()
69+ {
70+ switch item.element
71+ {
72+ case .text(let text):
73+ views.append(createTextView(with: text))
74+ case .image(let images):
75+ self.data = images
76+ default:
77+ break
78+ }
79+ }
80+ setUpInStackView()
81+ }
82+
83+ func setUpInStackView(){
84+ let nameStackView = UIStackView(arrangedSubviews: [nameLabel, fullNameLabel])
85+ nameStackView.axis = .vertical
86+ contentView.addSubview(nameStackView)
87+ nameStackView.height(46)
88+ nameStackView.edgesToSuperview(excluding: .bottom, insets: .left(16) + .right(16))
89+
90+ let stackView = UIStackView(arrangedSubviews: views)
91+ stackView.axis = .vertical
92+ contentView.addSubview(stackView)
93+ stackView.height(300, relation: .equalOrLess, isActive: true)
94+ stackView.topToBottom(of: nameStackView)
95+ stackView.edgesToSuperview(excluding: .top, insets: .bottom(8) + .left(16) + .right(16))
96+ }
97+}
GDproject/Simple model/Post.swiftnew file+30
@@ -0,0 +1,30 @@
1+//
2+// Post.swift
3+// NewsFeed
4+//
5+// Created by cstore on 12/01/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import Foundation
10+import UIKit
11+
12+struct Post {
13+ var dataArray: [Media]
14+ var fromUser: User
15+ var atDate: String
16+
17+ init(dataArray: [Media], from: User, date: String)
18+ {
19+ self.dataArray = dataArray
20+ fromUser = from
21+ atDate = date
22+ }
23+}
24+
25+
26+enum Media{
27+ case text(String)
28+ case image([UIImage])
29+ case quote
30+}
GDproject/Simple model/User.swiftnew file+40
@@ -0,0 +1,40 @@
1+//
2+// User.swift
3+// NewsFeed
4+//
5+// Created by cstore on 12/01/2019.
6+// Copyright © 2019 drHSE. All rights reserved.
7+//
8+
9+import Foundation
10+import UIKit
11+
12+struct User {
13+ //var photo: UIImage? = #imageLiteral(resourceName: "image")
14+ var login: String
15+ var id: Int
16+ var surname: String?
17+ var fullName: String
18+ var initials: (surname: String, name: String, optional: String?)?
19+ var placeOfWork: String?
20+ var faculty: String?
21+
22+ init(name: String, id: Int, fullName: String) {
23+ self.login = name
24+ self.id = id
25+ self.fullName = fullName
26+ }
27+
28+ init(surname: String, name: String, optional: String?, emailName: String, id: Int, place: String?, faculty: String?)
29+ {
30+ self.id = id
31+ self.login = emailName
32+ self.initials = (surname, name, optional)
33+
34+ self.fullName = "\(surname) \(name) \(optional ?? "")"
35+ self.placeOfWork = place
36+ if let f = faculty {
37+ self.faculty = f
38+ }
39+ }
40+}
GDproject/AppDelegate.swift → GDproject/Supporting files/AppDelegate.swiftrenamed

The content is the same.

GDproject/Assets.xcassets/AppIcon.appiconset/Contents.json → GDproject/Supporting files/Assets.xcassets/AppIcon.appiconset/Contents.jsonrenamed

The content is the same.

GDproject/Assets.xcassets/Contents.json → GDproject/Supporting files/Assets.xcassets/Contents.jsonrenamed

The content is the same.

GDproject/Base.lproj/LaunchScreen.storyboard → GDproject/Supporting files/Base.lproj/LaunchScreen.storyboardrenamed

The content is the same.

GDproject/ViewController.swiftdeleted−20
@@ -1,20 +0,0 @@
1−//
2−// ViewController.swift
3−// GDproject
4−//
5−// Created by cstore on 13/02/2019.
6−// Copyright © 2019 drHSE. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class ViewController: UIViewController {
12−
13− override func viewDidLoad() {
14− super.viewDidLoad()
15− // Do any additional setup after loading the view, typically from a nib.
16− }
17−
18−
19−}
20−