on a0a6486 help sign in
23 files changed+427−1204
since splitsnapshots
unifiedsplit
Cartfile+1−4 Cartfile.resolved+1−1 Melk.xcodeproj/project.pbxproj+40−92 Melk.xcodeproj/xcuserdata/ilya.xcuserdatad/xcschemes/Melk.xcscheme+3−3 Melk/AppDelegate.swift+3−1 Melk/CardContainer.swift−100 Melk/CardView.swift+10−126 Melk/CollectionView.swift+2−4 Melk/LocalVKDataTypes.swift+91−137 Melk/MainCoordinator.swift+14−30 Melk/MainViewController.swift+4−26 Melk/SecondaryCoordinator.swift+1−24 Melk/SecondaryViewController.swift+9−125 Melk/StackView.swift+1−3 Melk/Streaming.swift−195 Melk/StreamingParser.swift−80 Melk/StreamingService.swift−61 Melk/TableViewCells.swift+3−12 Melk/VKData.swift+34−34 Melk/VKPublicCrap.swift+3−6 Melk/VKServer.swift−123 Melk/VkServices.swift+207 README.md−17
Cartfile+1−4
@@ -1,8 +1,5 @@
11github "Alamofire/Alamofire"
2−# github "WE-St0r/SwiftyVK"
2+github "WE-St0r/SwiftyVK"
33github "kean/Nuke" ~> 4.0
44github "realm/realm-cocoa.git"
55github "tidwall/SwiftWebSocket"
6−# github "SwiftyJSON/SwiftyJSON"
7−# github "utahiosmac/Marshal"
8−github "Anviking/Decodable"
Cartfile.resolved+1−1
@@ -1,5 +1,5 @@
11github "Alamofire/Alamofire" "4.5.0"
2−github "Anviking/Decodable" "v0.5.1"
2+github "WE-St0r/SwiftyVK" "2.0.8"
33github "kean/Nuke" "4.1.2"
44github "realm/realm-cocoa" "v2.8.3"
55github "tidwall/SwiftWebSocket" "2.6.5"
Melk.xcodeproj/project.pbxproj+40−92
@@ -10,10 +10,8 @@
1010 0919AEA71F0D3D9D00894FFA /* SecondaryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919AEA61F0D3D9D00894FFA /* SecondaryViewController.swift */; };
1111 0919AEA91F0D459600894FFA /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919AEA81F0D459600894FFA /* CardView.swift */; };
1212 0919AEAD1F0D706700894FFA /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0919AEAC1F0D706700894FFA /* StackView.swift */; };
13− 09231E351F2394ED007C836D /* CardContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09231E341F2394ED007C836D /* CardContainer.swift */; };
1413 09939A561F097DA90014719D /* TableViewCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09939A551F097DA90014719D /* TableViewCells.swift */; };
1514 09A456361F0ED9A800BAC32D /* CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09A456351F0ED9A800BAC32D /* CollectionView.swift */; };
16− 09AFAB041F159C9200EBD200 /* StreamingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AFAB031F159C9200EBD200 /* StreamingService.swift */; };
1715 09B781591F11630D0007D2BF /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = 09B781581F11630D0007D2BF /* .gitignore */; };
1816 09BF41EF1F07F71F00AFAD57 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BF41EE1F07F71F00AFAD57 /* AppDelegate.swift */; };
1917 09BF41F61F07F71F00AFAD57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 09BF41F51F07F71F00AFAD57 /* Assets.xcassets */; };
@@ -25,41 +23,37 @@
2523 09BF42141F08341B00AFAD57 /* PublicCrap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BF42121F08341B00AFAD57 /* PublicCrap.swift */; };
2624 09BF42161F0834D400AFAD57 /* VKPublicCrap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BF42151F0834D400AFAD57 /* VKPublicCrap.swift */; };
2725 09BF42181F08352E00AFAD57 /* VKData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BF42171F08352E00AFAD57 /* VKData.swift */; };
26+ 09BF421A1F08357E00AFAD57 /* VkServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BF42191F08357E00AFAD57 /* VkServices.swift */; };
27+ 09BF42261F0835B200AFAD57 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42021F080A5700AFAD57 /* Alamofire.framework */; };
28+ 09BF42271F0835B200AFAD57 /* Alamofire.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42021F080A5700AFAD57 /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
29+ 09BF42281F0835B200AFAD57 /* Nuke.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42031F080A5700AFAD57 /* Nuke.framework */; };
30+ 09BF42291F0835B200AFAD57 /* Nuke.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42031F080A5700AFAD57 /* Nuke.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
31+ 09BF422A1F0835B200AFAD57 /* Realm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42041F080A5700AFAD57 /* Realm.framework */; };
32+ 09BF422B1F0835B200AFAD57 /* Realm.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42041F080A5700AFAD57 /* Realm.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
33+ 09BF422C1F0835B200AFAD57 /* RealmSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42051F080A5700AFAD57 /* RealmSwift.framework */; };
34+ 09BF422D1F0835B200AFAD57 /* RealmSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42051F080A5700AFAD57 /* RealmSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
35+ 09BF422E1F0835B200AFAD57 /* SwiftyVK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42061F080A5700AFAD57 /* SwiftyVK.framework */; };
36+ 09BF422F1F0835B200AFAD57 /* SwiftyVK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42061F080A5700AFAD57 /* SwiftyVK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
2837 09BF42321F08388100AFAD57 /* SecondaryCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BF42311F08388100AFAD57 /* SecondaryCoordinator.swift */; };
38+ 09BF42341F083B5800AFAD57 /* SwiftWebSocket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42331F083B5800AFAD57 /* SwiftWebSocket.framework */; };
39+ 09BF42351F083B6000AFAD57 /* SwiftWebSocket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42331F083B5800AFAD57 /* SwiftWebSocket.framework */; };
40+ 09BF42361F083B6000AFAD57 /* SwiftWebSocket.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42331F083B5800AFAD57 /* SwiftWebSocket.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
2941 09BF42561F08413000AFAD57 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09BF42551F08413000AFAD57 /* MainViewController.swift */; };
30− 09F03F231F164E7E000CE916 /* StreamingParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F03F221F164E7E000CE916 /* StreamingParser.swift */; };
31− 09F03F261F165884000CE916 /* Decodable.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09F03F241F165876000CE916 /* Decodable.framework */; };
32− 09F03F271F165884000CE916 /* Decodable.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09F03F241F165876000CE916 /* Decodable.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
33− 09F03F281F165884000CE916 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AFAAFF1F159AE300EBD200 /* SwiftyJSON.framework */; };
34− 09F03F291F165884000CE916 /* SwiftyJSON.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09AFAAFF1F159AE300EBD200 /* SwiftyJSON.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
35− 09F03F2A1F165884000CE916 /* SwiftWebSocket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42331F083B5800AFAD57 /* SwiftWebSocket.framework */; };
36− 09F03F2B1F165884000CE916 /* SwiftWebSocket.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42331F083B5800AFAD57 /* SwiftWebSocket.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
37− 09F03F2C1F165884000CE916 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42021F080A5700AFAD57 /* Alamofire.framework */; };
38− 09F03F2D1F165884000CE916 /* Alamofire.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42021F080A5700AFAD57 /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
39− 09F03F2E1F165884000CE916 /* Nuke.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42031F080A5700AFAD57 /* Nuke.framework */; };
40− 09F03F2F1F165884000CE916 /* Nuke.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42031F080A5700AFAD57 /* Nuke.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
41− 09F03F301F165884000CE916 /* Realm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42041F080A5700AFAD57 /* Realm.framework */; };
42− 09F03F311F165884000CE916 /* Realm.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42041F080A5700AFAD57 /* Realm.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
43− 09F03F321F165884000CE916 /* RealmSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42051F080A5700AFAD57 /* RealmSwift.framework */; };
44− 09F03F331F165884000CE916 /* RealmSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 09BF42051F080A5700AFAD57 /* RealmSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
45− 09F03F361F1674ED000CE916 /* VKServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F03F351F1674ED000CE916 /* VKServer.swift */; };
46− 09F0D79E1F129DCB00A13751 /* Streaming.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F0D79D1F129DCB00A13751 /* Streaming.swift */; };
4742/* End PBXBuildFile section */
4843
4944/* Begin PBXCopyFilesBuildPhase section */
50− 09F03F341F165884000CE916 /* Embed Frameworks */ = {
45+ 09BF42301F0835B200AFAD57 /* Embed Frameworks */ = {
5146 isa = PBXCopyFilesBuildPhase;
5247 buildActionMask = 2147483647;
5348 dstPath = "";
5449 dstSubfolderSpec = 10;
5550 files = (
56− 09F03F311F165884000CE916 /* Realm.framework in Embed Frameworks */,
57− 09F03F291F165884000CE916 /* SwiftyJSON.framework in Embed Frameworks */,
58− 09F03F331F165884000CE916 /* RealmSwift.framework in Embed Frameworks */,
59− 09F03F271F165884000CE916 /* Decodable.framework in Embed Frameworks */,
60− 09F03F2F1F165884000CE916 /* Nuke.framework in Embed Frameworks */,
61− 09F03F2B1F165884000CE916 /* SwiftWebSocket.framework in Embed Frameworks */,
62− 09F03F2D1F165884000CE916 /* Alamofire.framework in Embed Frameworks */,
51+ 09BF422B1F0835B200AFAD57 /* Realm.framework in Embed Frameworks */,
52+ 09BF42271F0835B200AFAD57 /* Alamofire.framework in Embed Frameworks */,
53+ 09BF42361F083B6000AFAD57 /* SwiftWebSocket.framework in Embed Frameworks */,
54+ 09BF422F1F0835B200AFAD57 /* SwiftyVK.framework in Embed Frameworks */,
55+ 09BF422D1F0835B200AFAD57 /* RealmSwift.framework in Embed Frameworks */,
56+ 09BF42291F0835B200AFAD57 /* Nuke.framework in Embed Frameworks */,
6357 );
6458 name = "Embed Frameworks";
6559 runOnlyForDeploymentPostprocessing = 0;
@@ -70,11 +64,8 @@
7064 0919AEA61F0D3D9D00894FFA /* SecondaryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondaryViewController.swift; sourceTree = "<group>"; };
7165 0919AEA81F0D459600894FFA /* CardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = "<group>"; };
7266 0919AEAC1F0D706700894FFA /* StackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = "<group>"; };
73− 09231E341F2394ED007C836D /* CardContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardContainer.swift; sourceTree = "<group>"; };
7467 09939A551F097DA90014719D /* TableViewCells.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCells.swift; sourceTree = "<group>"; };
7568 09A456351F0ED9A800BAC32D /* CollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionView.swift; sourceTree = "<group>"; };
76− 09AFAAFF1F159AE300EBD200 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/iOS/SwiftyJSON.framework; sourceTree = SOURCE_ROOT; };
77− 09AFAB031F159C9200EBD200 /* StreamingService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamingService.swift; sourceTree = "<group>"; };
7869 09B781581F11630D0007D2BF /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = .gitignore; path = ../.gitignore; sourceTree = "<group>"; };
7970 09BF41EB1F07F71F00AFAD57 /* Melk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Melk.app; sourceTree = BUILT_PRODUCTS_DIR; };
8071 09BF41EE1F07F71F00AFAD57 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -86,19 +77,17 @@
8677 09BF42031F080A5700AFAD57 /* Nuke.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nuke.framework; path = Carthage/Build/iOS/Nuke.framework; sourceTree = SOURCE_ROOT; };
8778 09BF42041F080A5700AFAD57 /* Realm.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Realm.framework; path = Carthage/Build/iOS/Realm.framework; sourceTree = SOURCE_ROOT; };
8879 09BF42051F080A5700AFAD57 /* RealmSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RealmSwift.framework; path = Carthage/Build/iOS/RealmSwift.framework; sourceTree = SOURCE_ROOT; };
80+ 09BF42061F080A5700AFAD57 /* SwiftyVK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyVK.framework; path = Carthage/Build/iOS/SwiftyVK.framework; sourceTree = SOURCE_ROOT; };
8981 09BF420D1F0833A700AFAD57 /* LocalVKDataTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalVKDataTypes.swift; sourceTree = "<group>"; };
9082 09BF420F1F0833C100AFAD57 /* MainCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainCoordinator.swift; sourceTree = "<group>"; };
9183 09BF42111F08341B00AFAD57 /* MyWeirdness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyWeirdness.swift; sourceTree = "<group>"; };
9284 09BF42121F08341B00AFAD57 /* PublicCrap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicCrap.swift; sourceTree = "<group>"; };
9385 09BF42151F0834D400AFAD57 /* VKPublicCrap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VKPublicCrap.swift; sourceTree = "<group>"; };
9486 09BF42171F08352E00AFAD57 /* VKData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VKData.swift; sourceTree = "<group>"; };
87+ 09BF42191F08357E00AFAD57 /* VkServices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VkServices.swift; sourceTree = "<group>"; };
9588 09BF42311F08388100AFAD57 /* SecondaryCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondaryCoordinator.swift; sourceTree = "<group>"; };
9689 09BF42331F083B5800AFAD57 /* SwiftWebSocket.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftWebSocket.framework; path = Carthage/Build/iOS/SwiftWebSocket.framework; sourceTree = SOURCE_ROOT; };
9790 09BF42551F08413000AFAD57 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
98− 09F03F221F164E7E000CE916 /* StreamingParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamingParser.swift; sourceTree = "<group>"; };
99− 09F03F241F165876000CE916 /* Decodable.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Decodable.framework; path = Carthage/Build/iOS/Decodable.framework; sourceTree = SOURCE_ROOT; };
100− 09F03F351F1674ED000CE916 /* VKServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VKServer.swift; sourceTree = "<group>"; };
101− 09F0D79D1F129DCB00A13751 /* Streaming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Streaming.swift; sourceTree = "<group>"; };
10291/* End PBXFileReference section */
10392
10493/* Begin PBXFrameworksBuildPhase section */
@@ -106,57 +95,19 @@
10695 isa = PBXFrameworksBuildPhase;
10796 buildActionMask = 2147483647;
10897 files = (
109− 09F03F301F165884000CE916 /* Realm.framework in Frameworks */,
110− 09F03F281F165884000CE916 /* SwiftyJSON.framework in Frameworks */,
111− 09F03F321F165884000CE916 /* RealmSwift.framework in Frameworks */,
112− 09F03F261F165884000CE916 /* Decodable.framework in Frameworks */,
113− 09F03F2E1F165884000CE916 /* Nuke.framework in Frameworks */,
114− 09F03F2A1F165884000CE916 /* SwiftWebSocket.framework in Frameworks */,
115− 09F03F2C1F165884000CE916 /* Alamofire.framework in Frameworks */,
98+ 09BF422A1F0835B200AFAD57 /* Realm.framework in Frameworks */,
99+ 09BF42261F0835B200AFAD57 /* Alamofire.framework in Frameworks */,
100+ 09BF42341F083B5800AFAD57 /* SwiftWebSocket.framework in Frameworks */,
101+ 09BF422E1F0835B200AFAD57 /* SwiftyVK.framework in Frameworks */,
102+ 09BF422C1F0835B200AFAD57 /* RealmSwift.framework in Frameworks */,
103+ 09BF42281F0835B200AFAD57 /* Nuke.framework in Frameworks */,
104+ 09BF42351F083B6000AFAD57 /* SwiftWebSocket.framework in Frameworks */,
116105 );
117106 runOnlyForDeploymentPostprocessing = 0;
118107 };
119108/* End PBXFrameworksBuildPhase section */
120109
121110/* Begin PBXGroup section */
122− 09231E331F2394C5007C836D /* Card */ = {
123− isa = PBXGroup;
124− children = (
125− 0919AEA81F0D459600894FFA /* CardView.swift */,
126− 09231E341F2394ED007C836D /* CardContainer.swift */,
127− );
128− name = Card;
129− sourceTree = "<group>";
130− };
131− 098397F71F1E887F008C88DD /* Main */ = {
132− isa = PBXGroup;
133− children = (
134− 09BF420F1F0833C100AFAD57 /* MainCoordinator.swift */,
135− 09BF42551F08413000AFAD57 /* MainViewController.swift */,
136− 09939A551F097DA90014719D /* TableViewCells.swift */,
137− );
138− name = Main;
139− sourceTree = "<group>";
140− };
141− 098397F81F1E888F008C88DD /* Secondary */ = {
142− isa = PBXGroup;
143− children = (
144− 09BF42311F08388100AFAD57 /* SecondaryCoordinator.swift */,
145− 0919AEA61F0D3D9D00894FFA /* SecondaryViewController.swift */,
146− );
147− name = Secondary;
148− sourceTree = "<group>";
149− };
150− 098397F91F1E88A3008C88DD /* Streaming */ = {
151− isa = PBXGroup;
152− children = (
153− 09AFAB031F159C9200EBD200 /* StreamingService.swift */,
154− 09F03F221F164E7E000CE916 /* StreamingParser.swift */,
155− 09F0D79D1F129DCB00A13751 /* Streaming.swift */,
156− );
157− name = Streaming;
158− sourceTree = "<group>";
159− };
160111 09A456341F0ED98800BAC32D /* Public */ = {
161112 isa = PBXGroup;
162113 children = (
@@ -185,16 +136,18 @@
185136 09BF41ED1F07F71F00AFAD57 /* Melk */ = {
186137 isa = PBXGroup;
187138 children = (
188− 098397F71F1E887F008C88DD /* Main */,
189− 098397F81F1E888F008C88DD /* Secondary */,
190− 098397F91F1E88A3008C88DD /* Streaming */,
191− 09231E331F2394C5007C836D /* Card */,
192139 09BF41EE1F07F71F00AFAD57 /* AppDelegate.swift */,
193140 09BF42111F08341B00AFAD57 /* MyWeirdness.swift */,
194141 09BF42121F08341B00AFAD57 /* PublicCrap.swift */,
195− 09F03F351F1674ED000CE916 /* VKServer.swift */,
142+ 09BF420F1F0833C100AFAD57 /* MainCoordinator.swift */,
143+ 09BF42311F08388100AFAD57 /* SecondaryCoordinator.swift */,
144+ 0919AEA81F0D459600894FFA /* CardView.swift */,
145+ 0919AEA61F0D3D9D00894FFA /* SecondaryViewController.swift */,
146+ 09BF42551F08413000AFAD57 /* MainViewController.swift */,
147+ 09939A551F097DA90014719D /* TableViewCells.swift */,
196148 09BF420D1F0833A700AFAD57 /* LocalVKDataTypes.swift */,
197149 09BF42151F0834D400AFAD57 /* VKPublicCrap.swift */,
150+ 09BF42191F08357E00AFAD57 /* VkServices.swift */,
198151 09BF42171F08352E00AFAD57 /* VKData.swift */,
199152 09BF41F51F07F71F00AFAD57 /* Assets.xcassets */,
200153 09BF41F71F07F71F00AFAD57 /* LaunchScreen.storyboard */,
@@ -210,13 +163,12 @@
210163 09BF420C1F080A5F00AFAD57 /* Dependencies */ = {
211164 isa = PBXGroup;
212165 children = (
213− 09F03F241F165876000CE916 /* Decodable.framework */,
214− 09AFAAFF1F159AE300EBD200 /* SwiftyJSON.framework */,
215166 09BF42331F083B5800AFAD57 /* SwiftWebSocket.framework */,
216167 09BF42021F080A5700AFAD57 /* Alamofire.framework */,
217168 09BF42031F080A5700AFAD57 /* Nuke.framework */,
218169 09BF42041F080A5700AFAD57 /* Realm.framework */,
219170 09BF42051F080A5700AFAD57 /* RealmSwift.framework */,
171+ 09BF42061F080A5700AFAD57 /* SwiftyVK.framework */,
220172 );
221173 name = Dependencies;
222174 sourceTree = "<group>";
@@ -231,7 +183,7 @@
231183 09BF41E71F07F71F00AFAD57 /* Sources */,
232184 09BF41E81F07F71F00AFAD57 /* Frameworks */,
233185 09BF41E91F07F71F00AFAD57 /* Resources */,
234− 09F03F341F165884000CE916 /* Embed Frameworks */,
186+ 09BF42301F0835B200AFAD57 /* Embed Frameworks */,
235187 );
236188 buildRules = (
237189 );
@@ -297,21 +249,17 @@
297249 buildActionMask = 2147483647;
298250 files = (
299251 09939A561F097DA90014719D /* TableViewCells.swift in Sources */,
300− 09F03F361F1674ED000CE916 /* VKServer.swift in Sources */,
301252 0919AEAD1F0D706700894FFA /* StackView.swift in Sources */,
302253 09BF42141F08341B00AFAD57 /* PublicCrap.swift in Sources */,
303254 09BF42161F0834D400AFAD57 /* VKPublicCrap.swift in Sources */,
304− 09F0D79E1F129DCB00A13751 /* Streaming.swift in Sources */,
305255 09BF42181F08352E00AFAD57 /* VKData.swift in Sources */,
306256 09BF42101F0833C100AFAD57 /* MainCoordinator.swift in Sources */,
307257 09A456361F0ED9A800BAC32D /* CollectionView.swift in Sources */,
308− 09231E351F2394ED007C836D /* CardContainer.swift in Sources */,
258+ 09BF421A1F08357E00AFAD57 /* VkServices.swift in Sources */,
309259 09BF42131F08341B00AFAD57 /* MyWeirdness.swift in Sources */,
310260 0919AEA91F0D459600894FFA /* CardView.swift in Sources */,
311261 09BF42321F08388100AFAD57 /* SecondaryCoordinator.swift in Sources */,
312262 09BF41EF1F07F71F00AFAD57 /* AppDelegate.swift in Sources */,
313− 09AFAB041F159C9200EBD200 /* StreamingService.swift in Sources */,
314− 09F03F231F164E7E000CE916 /* StreamingParser.swift in Sources */,
315263 09BF420E1F0833A700AFAD57 /* LocalVKDataTypes.swift in Sources */,
316264 09BF42561F08413000AFAD57 /* MainViewController.swift in Sources */,
317265 0919AEA71F0D3D9D00894FFA /* SecondaryViewController.swift in Sources */,
Melk.xcodeproj/xcuserdata/ilya.xcuserdatad/xcschemes/Melk.xcscheme+3−3
@@ -42,9 +42,9 @@
4242 </AdditionalOptions>
4343 </TestAction>
4444 <LaunchAction
45− buildConfiguration = "Release"
46− selectedDebuggerIdentifier = ""
47− selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
4848 launchStyle = "0"
4949 useCustomWorkingDirectory = "NO"
5050 ignoresPersistentStateOnLaunch = "NO"
Melk/AppDelegate.swift+3−1
@@ -7,7 +7,7 @@
77//
88
99import UIKit
10−//import SwiftyVK
10+import SwiftyVK
1111
1212@UIApplicationMain
1313class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -38,6 +38,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
3838 }
3939
4040 func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
41+ let app = options[.sourceApplication] as? String
42+ VK.process(url: url, sourceApplication: app)
4143 return true
4244 }
4345
Melk/CardContainer.swiftdeleted−100
@@ -1,100 +0,0 @@
1−//
2−// CardContainer.swift
3−// Melk
4−//
5−// Created by Ilya Kos on 7/22/17.
6−// Copyright © 2017 Ilya Kos. All rights reserved.
7−//
8−
9−import UIKit
10−
11−class CardContainer: UIView {
12−
13− func animate() {
14− blurView.effect = blur
15− card.transform = smallTransform
16− card.layer.opacity = 0
17− shadowView.layer.opacity = 0
18− shadowView.transform = smallTransform
19− shadowView.layer.shadowRadius = 0
20− UIView.animate(withDuration: 0.5, delay: 0, options: [.curveEaseInOut], animations: {
21− self.card.transform = self.normalTransform
22− self.shadowView.transform = self.normalTransform
23− self.shadowView.layer.shadowRadius = self.shadowRadius
24− self.shadowView.layer.opacity = 1
25− self.blurView.effect = nil
26− self.card.layer.opacity = 1
27− }, completion: nil)
28− }
29−
30− // MARK: Passthrough to CardView
31− var post: WallPost? {
32− get {
33− return card.post
34− }
35− set {
36− card.post = newValue
37− }
38− }
39−
40− var minWidth: CGFloat {
41− get {
42− return card.minWidth
43− }
44− set {
45− card.minWidth = newValue
46− }
47− }
48−
49−
50− var height: CGFloat {
51− get {
52− return card.height
53− }
54− set {
55− card.height = newValue
56− }
57− }
58−
59− private let card: CardView
60− private let blurView = UIVisualEffectView()
61− private let shadowView = UIView()
62− private let blur = UIBlurEffect(style: UIBlurEffectStyle.light)
63− private let scale: CGFloat = 0.5
64− private let smallTransform: CGAffineTransform
65− private let normalTransform = CGAffineTransform(scaleX: 1, y: 1)
66− private let shadowRadius: CGFloat = 12
67− private let shadowOpacity: Float = 0.15
68− private let shadowOffset: CGFloat = 16
69−
70− override init(frame: CGRect) {
71− card = CardView(frame: frame)
72− smallTransform = CGAffineTransform(scaleX: scale, y: scale)
73− super.init(frame: frame)
74− shadowView.layer.shadowColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).cgColor
75− shadowView.layer.shadowRadius = shadowRadius
76− shadowView.layer.shadowOpacity = shadowOpacity
77− shadowView.backgroundColor = UIColor.clear
78− shadowView.clipsToBounds = false
79− shadowView.layer.shadowOffset = CGSize.zero
80− addSubview(shadowView)
81− addSubview(card)
82− addSubview(blurView)
83− }
84−
85− required init?(coder aDecoder: NSCoder) {
86− fatalError("init(coder:) has not been implemented")
87− }
88−
89− override func layoutSubviews() {
90− super.layoutSubviews()
91− card.layoutIfNeeded()
92− self.frame = card.frame
93− shadowView.layer.shadowPath = CGPath(roundedRect: card.frame, cornerWidth: card.layer.cornerRadius, cornerHeight: card.layer.cornerRadius,
94− transform: nil)
95− shadowView.layer.shadowOffset.height = shadowOffset
96− shadowView.frame = card.frame
97− blurView.frame = CGRect(x: -shadowRadius, y: 0, width: card.frame.width + shadowRadius*2, height: card.frame.height + shadowRadius + shadowOffset)
98− }
99−
100−}
Melk/CardView.swift+10−126
@@ -12,51 +12,20 @@ class CardView: UIView {
1212
1313 var post: WallPost? {
1414 didSet {
15−// print(post?.owner)
1615 update()
1716 }
1817 }
19− var minWidth: CGFloat = 300 {
20− didSet {
21−// update()
22− }
23− }
24− var height: CGFloat = 400 {
25− didSet {
26−// update()
27− }
28− }
2918
3019 override init(frame: CGRect) {
3120 super.init(frame: frame)
3221 layer.masksToBounds = true
3322 layer.cornerRadius = 20
34− gradient.colors = [#colorLiteral(red: 0.9841352105, green: 0.9841352105, blue: 0.9841352105, alpha: 1).cgColor, #colorLiteral(red: 0.9456828237, green: 0.9456828237, blue: 0.9456828237, alpha: 1).cgColor]
35− gradient.startPoint = CGPoint(x: 0.5, y: 0)
36− gradient.endPoint = CGPoint(x: 0.5, y: 1)
37− layer.addSublayer(gradient)
38−// backgroundColor = #colorLiteral(red: 0.9638966278, green: 0.9734401588, blue: 0.9734401588, alpha: 1)
23+ backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
3924 }
4025
4126 required init?(coder aDecoder: NSCoder) {
4227 fatalError("init(coder:) has not been implemented")
4328 }
44−
45− private let gradient = CAGradientLayer()
46−
47−
48− private let padding = CGPoint(x: 32, y: 32)
49− private let vPadding1: CGFloat = 16
50− private let vPadding2: CGFloat = 16
51− private var minTextHeight: CGFloat {
52− return CGFloat(height * 0.2)
53− }
54− private let gradientRatio: CGFloat = 0.2
55− private let minGradientAmount: CGFloat = 70
56− private let hiddenByGradient: CGFloat = 10
57− private var maxAttachmentDim: CGFloat {
58− return minWidth / 2.3
59− }
6029
6130// private let avatar = UIImage()
6231// private let name = UIImage()
@@ -65,13 +34,14 @@ class CardView: UIView {
6534 subviews.map {$0.removeFromSuperview()}
6635
6736 let largeStack = StackView(axis: .vertical, alignment: .left)
68− largeStack.padding = padding
37+ largeStack.padding = CGPoint(x: 32, y: 32)
6938 addSubview(largeStack)
7039
7140 let userView = StackView(axis: .horizontal, alignment: .center)
41+// userView.backgroundColor = #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)
7242
7343
74− let avatarDim: CGFloat = 64
44+ let avatarDim: CGFloat = 50
7545 let avatar = UIImageView()
7646 post?.owner?.avatar?.load(into: avatar)
7747 avatar.layer.cornerRadius = avatarDim/2
@@ -81,116 +51,30 @@ class CardView: UIView {
8151 avatar.frame.size = CGSize(width: avatarDim, height: avatarDim)
8252 userView.addArrangedSubview(.view(avatar))
8353
84− userView.addArrangedSubview(.spacer(16))
54+ userView.addArrangedSubview(.spacer(8))
8555
8656 let userName = UILabel()
8757 let firstName = post?.owner?.firstName ?? ""
8858 let lastName = post?.owner?.lastName ?? ""
8959 userName.text = "\(firstName) \(lastName)"
9060 userName.font = UIFont.systemFont(ofSize: 28, weight: UIFontWeightHeavy)
91− userName.textColor = UIColor.darkText
9261 userName.sizeToFit()
9362 userView.addArrangedSubview(.view(userName))
94−
95− userView.layoutIfNeeded()
63+ userView.frame.origin = CGPoint(x: 16, y: 16)
9664
9765 largeStack.addArrangedSubview(.view(userView))
9866
99− largeStack.addArrangedSubview(.spacer(vPadding1))
100−
101−
102− let width = max(minWidth - 2 * padding.x, userView.frame.width)
103−
104−
105− let photoView = CollectionView()
106− photoView.alignment = .top
107− photoView.horizontalPadding = 8
108− photoView.verticalPadding = 8
109− photoView.padding = CGPoint.zero
110− photoView.maxWidth = width
111− var maxPhotoDim: CGFloat = maxAttachmentDim
112− if let attachments = post?.attachments {
113− for attachment in attachments {
114− if let v = attachment.value {
115− switch v {
116− case .photo(let photo):
117− if var pWidth = photo.width.value >>> {CGFloat($0)},
118− var pHeight = photo.height.value >>> {CGFloat($0)} {
119− let photoV = UIImageView()
120− photoV.layer.minificationFilter = kCAFilterTrilinear
121− photoV.contentMode = .scaleAspectFill
122− photo.image?.load(into: photoV)
123− var k: CGFloat!
124− if pWidth > pHeight {
125− k = CGFloat(pWidth) / maxPhotoDim
126− } else {
127− k = CGFloat(pHeight) / maxPhotoDim
128− }
129− pWidth /= k
130− pHeight /= k
131− photoV.frame.size = CGSize(width: pWidth, height: pHeight)
132− photoView.addArrangedSubview(photoV)
133− }
134−
135− default:
136− break // TODO: Handle other data types
137− }
138− }
139− }
140− }
141− photoView.layoutIfNeeded()
142−
143− var textHeight = height
144− textHeight -= padding.y * 2 + vPadding1 + userView.frame.height
145− if let count = post?.attachments.count{
146− if count > 0 {
147− textHeight -= vPadding2 + photoView.frame.height
148− }
149− }
150− print(textHeight)
151− textHeight = max(textHeight, minTextHeight)
152− print(textHeight)
67+ largeStack.addArrangedSubview(.spacer(16))
15368
15469 let body = UILabel()
15570 body.numberOfLines = 0
156− let bodyWidth: Double = Double(width)
71+ let bodyWidth: Double = 300
15772 body.font = UIFont.systemFont(ofSize: 22, weight: UIFontWeightSemibold)
158− body.text = post?.body
159− body.textColor = UIColor.darkText
73+ body.text = post?.body ?? "Spicy jalapeno flank landjaeger sausage tongue tail fatback frankfurter. Meatball tongue tail short ribs pastrami. Short ribs chicken pig tenderloin sausage pork. Corned beef t-bone pancetta jerky chuck picanha venison, turducken tenderloin shoulder boudin drumstick hamburger. Pork meatball meatloaf prosciutto pig andouille. Sirloin bacon hamburger short ribs pork cupim shank biltong turducken bresaola kevin prosciutto shoulder meatball. Strip steak frankfurter pork chop biltong jowl beef rump venison pancetta turkey tongue."
16074 let size = body.textRect(forBounds: CGRect(x: 0, y: 0, width: bodyWidth, height: Double.infinity), limitedToNumberOfLines: 0).size
161− body.frame.size.width = size.width
162− if size.height > textHeight {
163− body.frame.size.height = textHeight
164− let maskView = UIView()
165− let maskLayer = CAGradientLayer()
166− maskLayer.colors = [UIColor.black.cgColor, UIColor.clear.cgColor]
167− maskLayer.endPoint = CGPoint(x: 0.5, y: 1 - (hiddenByGradient/textHeight))
168− let minPoint = minGradientAmount / textHeight
169− maskLayer.startPoint = CGPoint(x: 0.5, y: 1 - max(minPoint, gradientRatio))
170− print(maskLayer.startPoint)
171− maskLayer.frame = body.bounds
172− maskView.frame = body.bounds
173− maskView.layer.addSublayer(maskLayer)
174− body.mask = maskView
175− } else {
176− body.frame.size.height = size.height
177− }
75+ body.frame.size = size
17876
17977 largeStack.addArrangedSubview(.view(body))
18078
181− if let count = post?.attachments.count{
182− if count > 0 {
183− largeStack.addArrangedSubview(.spacer(vPadding2))
184− largeStack.addArrangedSubview(.view(photoView))
185− }
186− }
187−
188− largeStack.layoutIfNeeded()
189−
190− frame.size = CGSize(width: width + padding.x * 2, height: min(height, largeStack.frame.height))
191−
192− gradient.frame = self.bounds
193− gradient.endPoint = CGPoint(x: 0.5, y: bounds.height / height)
194−
19579 }
19680}
Melk/CollectionView.swift+2−4
@@ -68,7 +68,7 @@ class CollectionView: UIView {
6868 var firstStack = true
6969
7070 for view in arrangedSubviews {
71−// print("new view")
71+ print("new view")
7272 if firstView {
7373 lastStack.addArrangedSubview(.view(view))
7474 firstView = false
@@ -94,9 +94,7 @@ class CollectionView: UIView {
9494 }
9595 }
9696 lastStack.layoutIfNeeded()
97− if !firstStack {
98− largeStack.addArrangedSubview(.spacer(verticalPadding))
99− }
97+ largeStack.addArrangedSubview(.spacer(verticalPadding))
10098 largeStack.addArrangedSubview(.view(lastStack))
10199 largeStack.frame.origin = CGPoint.zero
102100 largeStack.layoutIfNeeded()
Melk/LocalVKDataTypes.swift+91−137
@@ -11,8 +11,7 @@ import RealmSwift
1111import Alamofire
1212import CoreLocation
1313import Nuke
14−import SwiftyJSON
15−//import SwiftyVK
14+import SwiftyVK
1615
1716
1817typealias Token = String
@@ -293,25 +292,17 @@ class User: Object {
293292 }
294293 }
295294
296−// func get(completion: ((User?) -> ())? = nil) {
297−// VK.API.Users.get([VK.Arg.userIDs: "\(id)"]).send(onSuccess: { (response) in
298−// if let json = response.array?.first {
299−// let us = VKData.processUser(json: json)
300−// completion?(us)
301−// } else {
302−// completion?(nil)
303−// }
304−// }, onError: { (error) in
305−// completion?(nil)
306−// })
307−// }
308295 func get(completion: ((User?) -> ())? = nil) {
309− VKServer.get(user: self) { (data) in
310− if let json = JSON.init(data: data)["response"].array?.first {
311− let user = VKData.processUser(json: json)
312− completion?(user)
296+ VK.API.Users.get([VK.Arg.userIDs: "\(id)"]).send(onSuccess: { (response) in
297+ if let json = response.array?.first {
298+ let us = VKData.processUser(json: json)
299+ completion?(us)
300+ } else {
301+ completion?(nil)
313302 }
314− }
303+ }, onError: { (error) in
304+ completion?(nil)
305+ })
315306 }
316307
317308
@@ -502,19 +493,19 @@ class Message: GenericMessage, Comparable, SortedArrayItem {
502493 }
503494 }
504495
505−// func get(completion: ((Message?) -> ())? = nil) {
506−// VK.API.Messages.getById([VK.Arg.messageIds: String(id)]).send(onSuccess: { (response) in
507−// if let json = response.array?.first {
508−// let mes = VKData.processMessage(response)
509−// completion?(mes)
510−// } else {
511−// completion?(nil)
512−// }
513−// }, onError: { (error) in
514−// completion?(nil)
515−// })
516−// // TODO: Implement propperly?
517−// }
496+ func get(completion: ((Message?) -> ())? = nil) {
497+ VK.API.Messages.getById([VK.Arg.messageIds: String(id)]).send(onSuccess: { (response) in
498+ if let json = response.array?.first {
499+ let mes = VKData.processMessage(response)
500+ completion?(mes)
501+ } else {
502+ completion?(nil)
503+ }
504+ }, onError: { (error) in
505+ completion?(nil)
506+ })
507+ // TODO: Implement propperly?
508+ }
518509
519510 class func by(id: MessageID) -> Message {
520511 let realm = try! Realm()
@@ -1248,32 +1239,24 @@ class Photo: Object {
12481239 }
12491240 }
12501241
1251−// func get(completion: ((Photo?) -> ())? = nil) {
1252−// if let ownerID = owner?.id {
1253−// var ph = "\(ownerID)_\(id)"
1254−// if let key = accessKey {
1255−// ph.append("_\(key)")
1256−// }
1257−// VK.API.Photos.getById([VK.Arg.photos: ph]).send(onSuccess: { (response) in
1258−// if let json = response.array?.first {
1259−// let photo = VKData.processPhoto(json)
1260−// completion?(photo)
1261−// } else {
1262−// completion?(nil)
1263−// }
1264−// }, onError: { (error) in
1265−// completion?(nil)
1266−// })
1267−// } else {
1268−// completion?(nil)
1269−// }
1270−// }
12711242 func get(completion: ((Photo?) -> ())? = nil) {
1272− VKServer.get(photo: self) { data in
1273− if let json = JSON.init(data: data)["response"].array?.first {
1274− let photo = VKData.processPhoto(json)
1275− completion?(photo)
1243+ if let ownerID = owner?.id {
1244+ var ph = "\(ownerID)_\(id)"
1245+ if let key = accessKey {
1246+ ph.append("_\(key)")
12761247 }
1248+ VK.API.Photos.getById([VK.Arg.photos: ph]).send(onSuccess: { (response) in
1249+ if let json = response.array?.first {
1250+ let photo = VKData.processPhoto(json)
1251+ completion?(photo)
1252+ } else {
1253+ completion?(nil)
1254+ }
1255+ }, onError: { (error) in
1256+ completion?(nil)
1257+ })
1258+ } else {
1259+ completion?(nil)
12771260 }
12781261 }
12791262
@@ -1383,42 +1366,33 @@ class WallPost: Object {
13831366 // self.copyOwnerID = copyOwnerID
13841367 // }
13851368
1386−// func get(completion: ((WallPost?) -> ())? = nil) {
1387−// if let ownerID = owner?.id {
1388−// var ph = "\(ownerID)_\(id)"
1389−// // if let key = accessKey {
1390−// // ph.append("_\(key)")
1391−// // }
1392−// VK.API.Wall.getById([VK.Arg.posts: ph]).send(onSuccess: { (response) in
1393−// if let json = response.array?.first {
1394−// let photo = VKData.processWallPost(json)
1395−// completion?(photo)
1396−// } else {
1397−// completion?(nil)
1398−// }
1399−// }, onError: { (error) in
1400−// completion?(nil)
1401−// })
1402−// } else {
1403−// completion?(nil)
1404−// }
1405−// }
14061369 func get(completion: ((WallPost?) -> ())? = nil) {
1407− VKServer.get(wallPost: self) { (data) in
1408− if let json = JSON.init(data: data)["response"].array?.first {
1409− let post = VKData.processWallPost(json)
1410− completion?(post)
1411− }
1370+ if let ownerID = owner?.id {
1371+ var ph = "\(ownerID)_\(id)"
1372+ // if let key = accessKey {
1373+ // ph.append("_\(key)")
1374+ // }
1375+ VK.API.Wall.getById([VK.Arg.posts: ph]).send(onSuccess: { (response) in
1376+ if let json = response.array?.first {
1377+ let photo = VKData.processWallPost(json)
1378+ completion?(photo)
1379+ } else {
1380+ completion?(nil)
1381+ }
1382+ }, onError: { (error) in
1383+ completion?(nil)
1384+ })
1385+ } else {
1386+ completion?(nil)
14121387 }
14131388 }
1414−
14151389
14161390
14171391 override class func primaryKey() -> String? {
14181392 return "id"
14191393 }
14201394
1421− class func by(id: WallPostID) -> WallPost {
1395+ class func by(id: UserID) -> WallPost {
14221396 let realm = try! Realm()
14231397 if let us = realm.object(ofType: WallPost.self, forPrimaryKey: id) {
14241398 return us
@@ -1458,10 +1432,6 @@ class WallPostReply: Object {
14581432 }
14591433 }
14601434
1461− func get(completion: (() -> ())) {
1462− // TODO: Get wallPostReply
1463− }
1464−
14651435 override class func primaryKey() -> String? {
14661436 return "id"
14671437 }
@@ -1742,32 +1712,24 @@ class Video: Object {
17421712 }
17431713 }
17441714
1745−// func get(completion: ((Video?) -> ())? = nil) {
1746−// if let peerID = owner?.id {
1747−// var vi = "\(peerID)_\(id)"
1748−// if let key = accessKey {
1749−// vi.append("_\(key)")
1750−// }
1751−// VK.API.Video.get([VK.Arg.videos: vi]).send(onSuccess: { (response) in
1752−// if let json = response["items"].array?.first {
1753−// let video = VKData.processVideo(json)
1754−// completion?(video)
1755−// } else {
1756−// completion?(nil)
1757−// }
1758−// }, onError: { (error) in
1759−// completion?(nil)
1760−// })
1761−// } else {
1762−// completion?(nil)
1763−// }
1764−// }
17651715 func get(completion: ((Video?) -> ())? = nil) {
1766− VKServer.get(video: self) { (data) in
1767− if let json = JSON.init(data: data)["response"].array?.first {
1768− let video = VKData.processVideo(json)
1769− completion?(video)
1716+ if let peerID = owner?.id {
1717+ var vi = "\(peerID)_\(id)"
1718+ if let key = accessKey {
1719+ vi.append("_\(key)")
17701720 }
1721+ VK.API.Video.get([VK.Arg.videos: vi]).send(onSuccess: { (response) in
1722+ if let json = response["items"].array?.first {
1723+ let video = VKData.processVideo(json)
1724+ completion?(video)
1725+ } else {
1726+ completion?(nil)
1727+ }
1728+ }, onError: { (error) in
1729+ completion?(nil)
1730+ })
1731+ } else {
1732+ completion?(nil)
17711733 }
17721734 }
17731735
@@ -1874,32 +1836,24 @@ class Document: Object {
18741836 }
18751837 }
18761838
1877−// func get(completion: ((Document?) -> ())? = nil) {
1878−// if let ownerID = owner?.id {
1879−// var doc = "\(ownerID)_\(id)"
1880−// // if let key = accessKey {
1881−// // doc.append("_\(key)")
1882−// // }
1883−// VK.API.Docs.getById([VK.Arg.docs: doc]).send(onSuccess: { response in
1884−// if let json = response.array?.first {
1885−// let document = VKData.processDocument(json)
1886−// completion?(document)
1887−// } else {
1888−// completion?(nil)
1889−// }
1890−// }, onError: { (error) in
1891−// completion?(nil)
1892−// })
1893−// } else {
1894−// completion?(nil)
1895−// }
1896−// }
18971839 func get(completion: ((Document?) -> ())? = nil) {
1898− VKServer.get(doc: self) { (data) in
1899− if let json = JSON.init(data: data)["response"].array?.first {
1900− let doc = VKData.processDocument(json)
1901− completion?(doc)
1902− }
1840+ if let ownerID = owner?.id {
1841+ var doc = "\(ownerID)_\(id)"
1842+ // if let key = accessKey {
1843+ // doc.append("_\(key)")
1844+ // }
1845+ VK.API.Docs.getById([VK.Arg.docs: doc]).send(onSuccess: { response in
1846+ if let json = response.array?.first {
1847+ let document = VKData.processDocument(json)
1848+ completion?(document)
1849+ } else {
1850+ completion?(nil)
1851+ }
1852+ }, onError: { (error) in
1853+ completion?(nil)
1854+ })
1855+ } else {
1856+ completion?(nil)
19031857 }
19041858 }
19051859
@@ -2099,7 +2053,7 @@ class Multichat: Object {
20992053 if let us = realm.object(ofType: Multichat.self, forPrimaryKey: id) {
21002054 return us
21012055 } else {
2102−// VkServices.getMultichat(for: id)
2056+ VkServices.getMultichat(for: id)
21032057 let us = Multichat()
21042058 realmWrite { realm in
21052059 us.id = id
Melk/MainCoordinator.swift+14−30
@@ -7,8 +7,7 @@
77//
88
99import UIKit
10−import RealmSwift
11−//import SwiftyVK
10+import SwiftyVK
1211
1312class MainCoordinator {
1413 let window: UIWindow
@@ -16,49 +15,35 @@ class MainCoordinator {
1615 let loadingVC = UIViewController() // TODO: An actual loading VC
1716 let navC: UINavigationController!
1817 let secondaryCoord = SecondaryCoordinator()
19− let stream = StreamingService()
2018 init(window: UIWindow) {
2119 self.window = window
2220 window.rootViewController = loadingVC
2321
24− Realm.Configuration.defaultConfiguration = Realm.Configuration
25− .init(inMemoryIdentifier: "com.ilyakooo0.Melk.realm",
26− readOnly: false,
27− deleteRealmIfMigrationNeeded: true)
2822
2923 navC = UINavigationController(rootViewController: mainVC)
30−
31− mainVC.present = { tags in
32− if tags.count > 0 {
33− self.secondaryCoord.present(tag: tags.first!)
34− self.stream.rules = tags
35− self.stream.connect()
36− }
37− }
3824 updateScreens()
39− stream.handleResult = { result in
40− self.secondaryCoord.add(result: result)
41−// switch result {
42−// case .post(let post):
43−//
44−// }
45− }
25+
4626 }
4727
4828 func start() {
49−// VK.configure(withAppId: appID, delegate: self)
50−// if VK.state != .authorized {
51−// VK.logIn()
52−// }
53− print("didAuthorize")
54− window.rootViewController = navC
29+ VK.configure(withAppId: appID, delegate: self)
30+ if VK.state == .authorized {
31+ authorized()
32+ } else {
33+ VK.logIn()
34+ }
5535 }
5636
5737 func updateScreens() {
5838 secondaryCoord.updateScreens()
5939 }
40+
41+ fileprivate func authorized() {
42+ print("didAuthorize")
43+ window.rootViewController = navC
44+ }
6045}
61−/*
46+
6247extension MainCoordinator: VKDelegate {
6348 /** ---DEPRECATED. TOKEN NOW STORED IN KEYCHAIN--- Called when SwiftyVK need know where a token is located
6449 - returns: Path to save/read token or nil if should save token to UserDefaults*/
@@ -108,4 +93,3 @@ extension MainCoordinator: VKDelegate {
10893 }
10994
11095}
111− */
Melk/MainViewController.swift+4−26
@@ -10,9 +10,7 @@ import UIKit
1010
1111class MainViewController: UIViewController {
1212
13− var present: (([String]) -> ())?
14−
15− private let mainView = MainView()
13+ let mainView = MainView()
1614
1715 init() {
1816 super.init(nibName: nil, bundle: nil)
@@ -28,10 +26,8 @@ class MainViewController: UIViewController {
2826 fatalError("init(coder:) has not been implemented")
2927 }
3028
31− @objc private func presentTags() {
32− present?(
33− mainView.tags.flatMap({$0}).filter({$0 != ""})
34− )
29+ func presentTags() {
30+
3531 }
3632}
3733
@@ -47,8 +43,6 @@ class MainView: UIView {
4743 tableView.rowHeight = UITableViewAutomaticDimension
4844 tableView.register(TitleTableViewCell.self, forCellReuseIdentifier: TitleTableViewCell.identifier)
4945 tableView.register(TagTableViewCell.self, forCellReuseIdentifier: TagTableViewCell.identifier)
50− tableView.separatorStyle = .none
51− tableView.allowsSelection = false
5246 setNeedsLayout()
5347 }
5448
@@ -56,17 +50,6 @@ class MainView: UIView {
5650 tableView.frame = bounds
5751 }
5852
59− fileprivate var tags: [String?] = [nil] {
60− didSet {
61− if tags.last! != nil && tags.last! != "" {
62− if tags.count < 10 {
63− tags.append(nil)
64− tableView.insertRows(at: [IndexPath.init(row: tags.count - 1, section: 0)], with: .automatic)
65− }
66− }
67− }
68− }
69−
7053 required init?(coder aDecoder: NSCoder) {
7154 fatalError("init(coder:) has not been implemented")
7255 }
@@ -77,18 +60,13 @@ extension MainView: UITableViewDataSource {
7760 if let cell = tableView.dequeueReusableCell(withIdentifier: TagTableViewCell.identifier) as? TagTableViewCell {
7861// cell.titleText = "Testing testing 1 2 3"
7962 cell.style = indexPath.item == 0 ? .large : .normal
80− let index = indexPath.row
81− cell.tagDidChange = { tag in
82− self.tags[index] = tag
83− }
84− cell.tagString = tags[index]
8563 return cell
8664 }
8765 return UITableViewCell()
8866 }
8967
9068 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
91− return tags.count
69+ return 3
9270 }
9371
9472 func numberOfSections(in tableView: UITableView) -> Int {
Melk/SecondaryCoordinator.swift+1−24
@@ -12,42 +12,19 @@ class SecondaryCoordinator {
1212
1313 var windows: [UIWindow] = []
1414
15− private var didStartPresenting = false
16− private var tag: String = ""
17−
18− func add(result: StreamingServiceResult) {
19− for vc in VCs {
20− vc.add(result: result)
21− }
22− }
23−
24− func present(tag newTag: String) {
25− didStartPresenting = true
26− self.tag = newTag
27− VCs.map({ $0.present(tag: newTag) })
28− }
29−
3015 init() {
3116
3217 }
3318
34− private var VCs: [SecondaryViewController] = []
35−
3619 func updateScreens() {
3720 windows.removeAll()
38− VCs.removeAll()
3921 for screen in UIScreen.screens.dropFirst() {
4022 let window = UIWindow(frame: screen.bounds)
4123 window.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
4224 window.screen = screen
4325 window.isHidden = false
44− let VC = SecondaryViewController()
45− VCs.append(VC)
46− window.rootViewController = VC
26+ window.rootViewController = SecondaryViewController()
4727 windows.append(window)
48− if didStartPresenting {
49− VC.present(tag: tag)
50− }
5128 }
5229 }
5330}
Melk/SecondaryViewController.swift+9−125
@@ -9,145 +9,29 @@
99import UIKit
1010
1111class SecondaryViewController: UIViewController {
12−
1312 init() {
1413 super.init(nibName: nil, bundle: nil)
15− self.view = sView
16− }
17−
18− func add(result: StreamingServiceResult) {
19− sView.add(result: result)
20− }
21−
22− func present(tag: String) {
23− sView.present(tag: tag)
14+ self.view = SecondaryView(frame: view.bounds)
2415 }
2516
2617 required init?(coder aDecoder: NSCoder) {
2718 fatalError("init(coder:) has not been implemented")
2819 }
29−
30− private let sView = SecondaryView()
3120}
3221
3322class SecondaryView: UIView {
34−
35− var mainTag: String? {
36− get {
37− return tagLabel.text
38− }
39− set {
40− tagLabel.text = newValue
41−
42− }
43− }
44−
45−
46− private let spacer: CGFloat = 32
47− private let bottomSpacer: CGFloat = 64
48− private let tagSpacer: CGFloat = 32
49− private let tagLabel = UILabel()
50− private let melkLabel = UILabel()
51−
52− func present(tag: String) {
53− UIView.perform(.delete, on: [melkLabel], options: [], animations: nil) { (_) in
54− self.melkLabel.removeFromSuperview()
55− self.mainTag = tag
56− self.tagLabel.sizeToFit()
57− self.layoutIfNeeded(animated: true)
58− }
59− }
60−
61− func add(result: StreamingServiceResult) {
62− switch result {
63− case .post(let post):
64− let card = CardContainer()
65− card.minWidth = min(bounds.width / 2.3, 550)
66− card.height = cardHeight
67− card.post = post
68− cards.addArrangedSubview(.spacer(spacer))
69− cards.addArrangedSubview(.view(card))
70− card.animate()
71− }
72− self.layoutIfNeeded(animated: true)
73−// self.setNeedsLayout(animated: true) // Doesn't work for some reason
74− }
75−
76−// private let card = CardView()
77− private let cards = StackView(axis: .horizontal, alignment: .top)
78−
7923 override init(frame: CGRect) {
8024 super.init(frame: frame)
81− backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
82− addSubview(cards)
83−
84− melkLabel.text = "Melk"
85− melkLabel.font = UIFont.systemFont(ofSize: 200, weight: UIFontWeightHeavy)
86− melkLabel.textColor = #colorLiteral(red: 0.9601849914, green: 0.9601849914, blue: 0.9601849914, alpha: 1)
87− addSubview(melkLabel)
88−
89− tagLabel.font = UIFont.systemFont(ofSize: 69, weight: UIFontWeightBold)
90− tagLabel.textColor = #colorLiteral(red: 0.3176470588, green: 0.3179988265, blue: 0.3179988265, alpha: 1)
91− addSubview(tagLabel)
92− }
93−
94− func setNeedsLayout(animated: Bool) {
95− self.animate = animated
96− self.setNeedsLayout()
97− }
98− func layoutIfNeeded(animated: Bool) {
99− self.animate = animated
100− self.layoutIfNeeded()
101− }
102− private var animate: Bool = false
103−
104− private func cleanCards() {
105− var offset = 0
106− outLoop: for (i, element) in cards.arrangedSubviews.enumerated() {
107− switch element {
108− case .view(let card):
109− let cardFrame = convert(card.frame, from: cards)
110− if cardFrame.intersects(bounds) {
111− break outLoop
112− } else {
113− cards.arrangedSubviews.remove(at: i-1-offset)
114− cards.arrangedSubviews.remove(at: i-1-offset)
115− offset += 2
116− }
117− case .spacer(_):
118− break
119− }
120− }
121− }
122−
123− private let padding = CGPoint(x: 32, y: 16)
124− private var cardHeight: CGFloat = 400
125−
126− override func layoutSubviews() {
127− super.layoutSubviews()
12825
129− melkLabel.sizeToFit()
130− melkLabel.center = center
26+ let card = CardView(frame: CGRect(x: 20, y: 20, width: 600, height: 300))
27+ let post = WallPost()
28+ post.owner = User()
29+ post.owner?.firstName = "David"
30+ post.owner?.avatar = RealmPhoto()
31+ post.owner?.avatar?.imageSURL = "https://static.independent.co.uk/s3fs-public/styles/article_small/public/thumbnails/image/2017/04/01/17/twitter-egg.jpg"
32+ card.post = post
33+ addSubview(card)
13134
132− let updates = {
133− self.tagLabel.sizeToFit()
134− self.tagLabel.center.x = self.center.x
135− self.tagLabel.frame.origin.y = self.tagSpacer
136− self.cards.frame.origin.y = self.tagLabel.frame.maxY + self.padding.y
137− self.cards.layoutIfNeeded()
138− self.cards.frame.origin.x = self.frame.width - self.padding.x - self.cards.frame.width
139− }
140− if animate {
141− UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.6, options: [], animations: updates, completion: { _ in
142− self.cleanCards()
143− })
144−// UIView.animate(withDuration: 0.4, delay: 0.0, options: [.curveEaseOut], animations: updates, completion: nil)
145− } else {
146− updates()
147− self.cleanCards()
148− }
149− cardHeight = bounds.height - tagLabel.frame.height - padding.y - tagSpacer - bottomSpacer
150− animate = false
15135 }
15236
15337 required init?(coder aDecoder: NSCoder) {
Melk/StackView.swift+1−3
@@ -44,8 +44,6 @@ class StackView: UIView {
4444 super.layoutSubviews()
4545 print("laying out subviews")
4646
47− subviews.map({$0.removeFromSuperview()}) // TODO: There must be a better way!
48−
4947 var height: CGFloat = 0
5048 var width: CGFloat = 0
5149 switch axis {
@@ -64,7 +62,7 @@ class StackView: UIView {
6462 height += a
6563 }
6664 case .view(let view):
67− view.layoutIfNeeded()
65+
6866 switch axis {
6967 case .horizontal:
7068 view.frame.origin.x = width
Melk/Streaming.swiftdeleted−195
@@ -1,195 +0,0 @@
1−//
2−// Streaming.swift
3−// Melk
4−//
5−// Created by Ilya Kos on 7/9/17.
6−// Copyright © 2017 Ilya Kos. All rights reserved.
7−//
8−
9−import Foundation
10−import SwiftWebSocket
11−import Alamofire
12−import SwiftyJSON
13−
14−class Streaming {
15−
16− let streamingServerSurl = "https://api.vk.com/method/streaming.getServerUrl"
17− let params: [String: String] = [
18− "access_token": accessKey,
19− "v": vkAPIVersion
20− ]
21−
22− private var key: String?
23− private var server: String?
24− let ws = WebSocket()
25−
26− var processItem: ((Any) -> ())?
27−
28− func getServer(completion: (() -> ())? = nil) {
29− Alamofire.request(streamingServerSurl, parameters: params).validate().responseData { (response) in
30− switch response.result {
31− case .success(let data):
32− let json = JSON.init(data: data)["response"]
33− self.key = json["key"].string
34− self.server = json["endpoint"].string
35− case .failure(let error):
36− print(error)
37− }
38− DispatchQueue.main.async {
39− completion?()
40− }
41− }
42− }
43−
44− func add(rule: Rule, completion: (() -> ())? = nil) {
45− if let key = key,
46− let server = server {
47− let url = "https://\(server)/rules?key=\(key)"
48− let request: [String: Any] = [
49− "rule": [
50− "value": rule.rule,
51− "tag": rule.tag
52− ]
53− ]
54− print(try? JSONSerialization.data(withJSONObject: request, options: .prettyPrinted) =>> {String.init(data: $0, encoding: .utf8)})
55− Alamofire.request(url, method: .post, parameters: request, encoding: JSONEncoding.default)
56− .validate().responseData(completionHandler: { (response) in
57− switch response.result {
58− case .success(let data):
59− let json = JSON.init(data: data)
60− print(json) // TODO: Handle error
61− case .failure(let error):
62− print(error)
63− }
64− DispatchQueue.main.async {
65− completion?()
66− }
67− })
68− } else {
69− getServer() {
70− self.add(rule: rule, completion: completion)
71− }
72− }
73− }
74− func add(rules: [Rule], completion: (() -> ())? = nil) {
75− if let server = server,
76− let key = key {
77− var numOfCompletions = rules.count + 1
78− let complete: (() -> ()) = {
79− numOfCompletions -= 1
80− if numOfCompletions == 0 {
81− completion?()
82− }
83− }
84−
85− complete()
86−
87− for rule in rules {
88− add(rule: rule, completion: complete)
89− }
90− } else {
91− getServer() {
92− self.add(rules: rules, completion: completion)
93− }
94− }
95− }
96− func getRules(completion: @escaping (([Rule]?) -> ())) {
97− if let server = server,
98− let key = key {
99− let url = "https://\(server)/rules?key=\(key)"
100− Alamofire.request(url, method: .get).validate().responseData { (response) in
101− switch response.result {
102− case .success(let data):
103− let json = JSON.init(data: data)
104− print(json)
105− if json["code"].int == 200 {
106− var resultRules: [Rule] = []
107− if let rules = json["rules"].array {
108− for rule in rules {
109− if let tag = rule["tag"].string,
110− let value = rule["value"].string {
111− resultRules.append((rule: value, tag: tag))
112− }
113− }
114− }
115− completion(resultRules)
116− } // TODO" Handle errors
117− case .failure(let error):
118− print(error) // TODO: HAndl;e error
119− }
120− }
121− } else {
122− getServer() {
123− self.getRules(completion: completion)
124− }
125− }
126− }
127− func remove(rule: Rule, completion: (() -> ())? = nil) {
128− if let server = server,
129− let key = key {
130− let url = "https://\(server)/rules?key=\(key)"
131− let request: [String: Any] = [
132− "tag": rule.tag
133− ]
134− Alamofire.request(url, method: .delete, parameters: request, encoding: JSONEncoding.default).validate().responseData { response in
135− switch response.result {
136− case .success(let data):
137− let json = JSON.init(data: data)
138− print(json) // TODO: HAndle error
139− completion?()
140− case .failure(let error):
141− print(error) // TODO: HAndl;e error
142− }
143− }
144− } else {
145− getServer() {
146− self.remove(rule: rule, completion: completion)
147− }
148− }
149− }
150− func removeAllRules(completion: (() -> ())? = nil) {
151− getRules { (rules) in
152− if let rules = rules {
153−
154− var numOfCompleted = rules.count + 1
155− let complete : (() -> ()) = {
156− numOfCompleted -= 1
157− if numOfCompleted == 0 {
158− completion?()
159− }
160− }
161−
162− complete()
163−
164− for rule in rules {
165− self.remove(rule: rule, completion: complete)
166− }
167− }
168− }
169− }
170− func connect(completion: (() -> ())? = nil) {
171− if let key = key,
172− let server = server {
173− let surl = "wss://\(server)/stream?key=\(key)"
174− let url = URL(string: surl)!
175− ws.event.message = { message in
176− self.processItem?(message)
177− }
178− let request = NSMutableURLRequest(url: url)
179− request.httpMethod = "GET"
180− request.addValue("upgrade", forHTTPHeaderField: "Connection")
181− request.addValue("websocket", forHTTPHeaderField: "Upgrade")
182− request.addValue("13", forHTTPHeaderField: "Sec-Websocket-Version")
183− ws.open(request: request as URLRequest)
184− DispatchQueue.main.async {
185− completion?()
186− }
187− } else {
188− getServer() {
189− self.connect(completion: completion)
190− }
191− }
192− }
193−}
194−
195−typealias Rule = (rule: String, tag: String)
Melk/StreamingParser.swiftdeleted−80
@@ -1,80 +0,0 @@
1−//
2−// StreamingParser.swift
3−// Melk
4−//
5−// Created by Ilya Kos on 7/12/17.
6−// Copyright © 2017 Ilya Kos. All rights reserved.
7−//
8−
9−import Foundation
10−import Decodable
11−
12−class StreamingParser {
13− static func parse(json: DJSON, completion: @escaping ((StreamingResponse) -> ())) {
14− do {
15− let code: Int = try json => "code"
16− switch code {
17− case 100:
18− let event = try json => "event"
19− let eventType: String = try event => "event_type"
20− let eventID = try event => "event_id"
21− let postID: WallPostID = try eventID => "post_id"
22− let ownerID: UserID = try eventID => "post_owner_id"
23− // let
24− var post: WallPost!
25− var comp = 2
26− realmWrite { _ in
27− post = WallPost.by(id: postID)
28− post.owner = User.by(id: ownerID)
29− switch eventType {
30− case "post":
31− break
32− case "comment":
33− /*
34− if let id: Int = try? eventID => "comment_id" {
35− let comment = WallPostReply.by(id: id)
36− comment.wallPost = post
37− comp += 1
38− comment // TODO: get comment
39− }
40− */
41− print("comment not implemented")
42−
43− case "share":
44− break
45− default:
46− print("error:\n\(json)")
47− }
48− }
49−// print(post.owner)
50− let complete = {
51− comp -= 1
52− if comp == 0 {
53−// print(post.owner)
54− completion(.post(post))
55− }
56− }
57− post.owner?.get(completion: { (_) in
58− complete()
59− })
60− post.get(completion: { (_) in
61− complete()
62− })
63− break // handle event
64− case 300:
65− break // handle service message
66− default:
67− print("Not implemented:\n\(json)\n")
68− }
69− } catch let error {
70− print(error)
71− }
72− }
73−}
74−
75−enum StreamingResponse {
76− case service
77− case post(WallPost)
78−}
79−
80−typealias DJSON = Any
Melk/StreamingService.swiftdeleted−61
@@ -1,61 +0,0 @@
1−//
2−// StreamingService.swift
3−// Melk
4−//
5−// Created by Ilya Kos on 7/12/17.
6−// Copyright © 2017 Ilya Kos. All rights reserved.
7−//
8−
9−import Foundation
10−
11−class StreamingService {
12− init() {
13− streaming.processItem = { item in
14− if let string = item as? String,
15− let data = string.data(using: .utf8),
16− let json = try? JSONSerialization.jsonObject(with: data, options: []) {
17− StreamingParser.parse(json: json, completion: { (result) in
18− switch result {
19− case .post(let post):
20− self.handleResult?(.post(post))
21− case .service:
22− break // TODO: HAndle servoce message
23− }
24− })
25− }
26− }
27− }
28− var rules: [String] = [] {
29− didSet {
30− updateRules()
31− }
32− }
33−
34− func connect() {
35− streaming.connect()
36− }
37−
38− var handleResult: ((StreamingServiceResult) -> ())?
39−
40−
41−
42− private let streaming = Streaming()
43−
44− private func updateRules() {
45− streaming.removeAllRules {
46− var outRules: [Rule] = []
47− var i = 1
48− for rule in self.rules {
49− if i <= 10 {
50− outRules.append((rule: rule, tag: String(i)))
51− i += 1
52− }
53− }
54− self.streaming.add(rules: outRules)
55− }
56− }
57−}
58−
59−enum StreamingServiceResult {
60− case post(WallPost)
61−}
Melk/TableViewCells.swift+3−12
@@ -57,12 +57,6 @@ class TagTableViewCell: UITableViewCell {
5757 }
5858 }
5959
60− var tagDidChange: ((String?) -> ())?
61−
62− @objc private func textDidChange() {
63− tagDidChange?(tagString)
64− }
65−
6660 var style: TagStyle = .normal {
6761 didSet {
6862 updateStyle()
@@ -76,9 +70,6 @@ class TagTableViewCell: UITableViewCell {
7670
7771 textField.borderStyle = .roundedRect
7872 textField.adjustsFontSizeToFitWidth = false
79− textField.autocapitalizationType = .none
80− textField.autocorrectionType = .no
81− textField.addTarget(self, action: #selector(self.textDidChange), for: .editingChanged)
8273
8374 contentView.addSubview(textField)
8475// textField.delegate = self
@@ -101,7 +92,7 @@ class TagTableViewCell: UITableViewCell {
10192 CGRect.infinite, limitedToNumberOfLines: 1)
10293 .height + 2*2
10394
104− let frame = CGRect(x: 16, y: style == .large ? 32 : 4, width: bounds.width - 16*2, height: height)
95+ let frame = CGRect(x: 16, y: 8, width: bounds.width - 16*2, height: height)
10596 textField.frame = frame
10697 print(textField.frame)
10798 }
@@ -112,8 +103,8 @@ class TagTableViewCell: UITableViewCell {
112103
113104
114105 static let identifier = "io.Melk.tagTableViewCell"
115− static let largeHeight: CGFloat = 37.5 + 16 + 32
116− static let normalHeight: CGFloat = 28.0 + 4*2
106+ static let largeHeight: CGFloat = 37.5 + 8*2
107+ static let normalHeight: CGFloat = 28.0 + 8*2
117108}
118109
119110//extension TagTableViewCell: UITextFieldDelegate {
Melk/VKData.swift+34−34
@@ -7,10 +7,10 @@
77//
88
99import Foundation
10−import SwiftyJSON
10+//import SwiftyJSON
1111import CoreLocation
1212import RealmSwift
13−//import SwiftyVK
13+import SwiftyVK
1414
1515class VKData {
1616 // var users: [UserID: User] = [:]
@@ -31,7 +31,7 @@ class VKData {
3131 // var polls: [PollID: Poll] = [:]
3232 // var photoAlbums: [PhotoAlbumID: PhotoAlbum] = [:]
3333
34− class func processUser(json: JSON) -> User? {
34+ class func processUser(json: SwiftyVK.JSON) -> User? {
3535 print("in")
3636 if let id = json["id"].int, let firstName = json["first_name"].string, let lastName = json["last_name"].string {
3737 var user: User!
@@ -49,7 +49,7 @@ class VKData {
4949 }
5050 user.birthday = formatter.date(from: birthday)
5151 }
52− user.avatar = RealmPhoto.by(user.avatarID, surl: json["photo_100"].string)// was "photo_max"
52+ user.avatar = RealmPhoto.by(user.avatarID, surl: json["photo_max"].string)
5353 user.photo = RealmPhoto.by(user.photoID, surl: json["photo_max_orig"].string)
5454 if let friendStat = json["friend_status"].int {
5555 user.friendStatus = FriendStatus(rawValue: friendStat)
@@ -90,7 +90,7 @@ class VKData {
9090 return nil
9191 }
9292
93− class func processGeolocation(_ json: JSON) -> Geolocation? {
93+ class func processGeolocation(_ json: SwiftyVK.JSON) -> Geolocation? {
9494 if let coords = json["coordinates"].string{
9595 let nums = coords.characters.split(separator: " ").map({ (n) -> Double? in
9696 NumberFormatter().number(from: String(n))?.doubleValue
@@ -112,7 +112,7 @@ class VKData {
112112 }
113113 }
114114
115− class func processMedia(_ json: JSON) -> Media? {
115+ class func processMedia(_ json: SwiftyVK.JSON) -> Media? {
116116 if let type = json["type"].string {
117117 switch type {
118118 case "photo":
@@ -174,7 +174,7 @@ class VKData {
174174 return nil
175175 }
176176
177− class func processPhotoAlbum(_ json: JSON) -> PhotoAlbum? {
177+ class func processPhotoAlbum(_ json: SwiftyVK.JSON) -> PhotoAlbum? {
178178 if let id = json["id"].int{
179179 var album: PhotoAlbum!
180180 realmWrite { _ in
@@ -209,7 +209,7 @@ class VKData {
209209 return nil
210210 }
211211
212− class func processGift(_ json: JSON) -> Gift? {
212+ class func processGift(_ json: SwiftyVK.JSON) -> Gift? {
213213 if let id = json["id"].int {
214214 var gift: Gift!
215215 realmWrite({ _ in
@@ -221,7 +221,7 @@ class VKData {
221221 return nil
222222 }
223223
224− class func processWallPostReply(_ json: JSON) -> WallPostReply? {
224+ class func processWallPostReply(_ json: SwiftyVK.JSON) -> WallPostReply? {
225225 let likes = json["likes"]
226226 if let id = json["id"].int {
227227 var reply: WallPostReply!
@@ -248,7 +248,7 @@ class VKData {
248248 return nil
249249 }
250250
251− class func processPollAnswer(_ json: JSON) -> PollAnswer? {
251+ class func processPollAnswer(_ json: SwiftyVK.JSON) -> PollAnswer? {
252252 if let id = json["id"].int,
253253 let body = json["text"].string,
254254 let votes = json["votes"].int,
@@ -258,7 +258,7 @@ class VKData {
258258 return nil
259259 }
260260
261− class func processPoll(_ json: JSON) -> Poll? {
261+ class func processPoll(_ json: SwiftyVK.JSON) -> Poll? {
262262 if let id = json["id"].int {
263263 var poll: Poll!
264264 realmWrite { _ in
@@ -279,7 +279,7 @@ class VKData {
279279 return nil
280280 }
281281
282− class func processPhoto(_ json: JSON) -> Photo? {
282+ class func processPhoto(_ json: SwiftyVK.JSON) -> Photo? {
283283 if let id = json["id"].int {
284284 var photo: Photo!
285285 realmWrite { _ in
@@ -289,13 +289,13 @@ class VKData {
289289 photo.width.value = json["width"].int
290290 photo.height.value = json["height"].int
291291 var surl: String?
292−// if let imageSurl = json["photo_2560"].string {
293−// surl = imageSurl
294−// } else if let imageSurl = json["photo_1280"].string {
295−// surl = imageSurl
296−// } else if let imageSurl = json["photo_807"].string {
297−// surl = imageSurl
298− /*} else*/ if let imageSurl = json["photo_604"].string {
292+ if let imageSurl = json["photo_2560"].string {
293+ surl = imageSurl
294+ } else if let imageSurl = json["photo_1280"].string {
295+ surl = imageSurl
296+ } else if let imageSurl = json["photo_807"].string {
297+ surl = imageSurl
298+ } else if let imageSurl = json["photo_604"].string {
299299 surl = imageSurl
300300 } else if let imageSurl = json["photo_130"].string {
301301 surl = imageSurl
@@ -312,7 +312,7 @@ class VKData {
312312 }
313313 }
314314
315− class func processVideo(_ json: JSON) -> Video? {
315+ class func processVideo(_ json: SwiftyVK.JSON) -> Video? {
316316 if let id = json["id"].int {
317317 var video: Video!
318318 realmWrite { _ in
@@ -337,7 +337,7 @@ class VKData {
337337 }
338338 }
339339
340− class func processAudio(_ json: JSON) -> Audio? {
340+ class func processAudio(_ json: SwiftyVK.JSON) -> Audio? {
341341 if let id = json["id"].int {
342342 var audio: Audio!
343343 realmWrite { _ in
@@ -354,7 +354,7 @@ class VKData {
354354 }
355355 }
356356
357− class func processDocument(_ json: JSON) -> Document? {
357+ class func processDocument(_ json: SwiftyVK.JSON) -> Document? {
358358 if let id = json["id"].int {
359359 var doc: Document!
360360 realmWrite { _ in
@@ -371,7 +371,7 @@ class VKData {
371371 return nil
372372 }
373373
374− class func processSticker(_ json: JSON) -> Sticker? {
374+ class func processSticker(_ json: SwiftyVK.JSON) -> Sticker? {
375375 if let id = json["id"].int,
376376 let pack = json["product_id"].int {
377377 var sticker: Sticker!
@@ -387,7 +387,7 @@ class VKData {
387387 return nil
388388 }
389389
390− class func processRating(_ json: JSON) -> Rating? {
390+ class func processRating(_ json: SwiftyVK.JSON) -> Rating? {
391391 if let stars = json["stars"].int,
392392 let reviewCount = json["reviews_count"].int {
393393 return Rating(stars: stars, reviewCount: reviewCount)
@@ -395,7 +395,7 @@ class VKData {
395395 return nil
396396 }
397397
398− class func processButton(_ json: JSON) -> LinkButton? {
398+ class func processButton(_ json: SwiftyVK.JSON) -> LinkButton? {
399399 if let title = json["title"].string,
400400 let surl = json["url"].string,
401401 let url = URL(string: surl) {
@@ -404,7 +404,7 @@ class VKData {
404404 return nil
405405 }
406406
407− class func processLink(_ json: JSON) -> Link? {
407+ class func processLink(_ json: SwiftyVK.JSON) -> Link? {
408408 if let surl = json["url"].string {
409409 var link: Link!
410410 realmWrite({ (_) in
@@ -422,7 +422,7 @@ class VKData {
422422 return nil
423423 }
424424
425− class func processWallPost(_ json: JSON) -> WallPost? {
425+ class func processWallPost(_ json: SwiftyVK.JSON) -> WallPost? {
426426 let comments = json["comments"]
427427 let likes = json["likes"]
428428 let reposts = json["reposts"]
@@ -430,7 +430,7 @@ class VKData {
430430 var post: WallPost!
431431 realmWrite { _ in
432432 post = WallPost.by(id: id)
433− post.owner = json["owner_id"].int >>> {User.by(id: $0)}
433+ post.owner = json["to_id"].int >>> {User.by(id: $0)}
434434 post.creator = json["from_id"].int >>> {User.by(id: $0)}
435435 post.date = json["date"].int >>> {Date.init(timeIntervalSince1970: TimeInterval($0))}
436436 post.body = json["text"].string
@@ -469,7 +469,7 @@ class VKData {
469469 return nil
470470 }
471471
472− class func prpocessServiceMessageAction(_ json: JSON) -> ServiceMessageAction? {
472+ class func prpocessServiceMessageAction(_ json: SwiftyVK.JSON) -> ServiceMessageAction? {
473473 if let sAction = json["action"].string {
474474 switch sAction {
475475 case "chat_photo_update":
@@ -519,7 +519,7 @@ class VKData {
519519 return nil
520520 }
521521
522− class func processMessage(_ json: JSON) -> Message? {
522+ class func processMessage(_ json: SwiftyVK.JSON) -> Message? {
523523 if let user = json["user_id"].int >>> {User.by(id: $0)},
524524 let date = json["date"].int >>> {Date(timeIntervalSince1970: TimeInterval($0))},
525525 let id = json["id"].int {
@@ -556,7 +556,7 @@ class VKData {
556556 }
557557 }
558558
559− class func processGenericMessage(_ json: JSON) -> GenericMessage? {
559+ class func processGenericMessage(_ json: SwiftyVK.JSON) -> GenericMessage? {
560560 if let user = json["user_id"].int >>> {User.by(id: $0)},
561561 let date = json["date"].int >>> {Date(timeIntervalSince1970: TimeInterval($0))} {
562562 let message = GenericMessage()
@@ -587,7 +587,7 @@ class VKData {
587587
588588
589589
590− class func processNotificationSettings(_ json: JSON) -> ChatNotificationSettings? {
590+ class func processNotificationSettings(_ json: SwiftyVK.JSON) -> ChatNotificationSettings? {
591591 if let sound = json["sound"].int,
592592 let date = json["disabled_until"].int {
593593 if date == -1 {
@@ -600,7 +600,7 @@ class VKData {
600600 }
601601 }
602602
603− class func processMultichat(_ json: JSON) -> Multichat? { // from .getChat
603+ class func processMultichat(_ json: SwiftyVK.JSON) -> Multichat? { // from .getChat
604604 if let id = json["id"].int {
605605 var chat: Multichat!
606606 realmWrite { _ in
@@ -634,7 +634,7 @@ class VKData {
634634 return nil
635635 }
636636
637− class func processDialog(_ json: JSON) -> Dialog? {
637+ class func processDialog(_ json: SwiftyVK.JSON) -> Dialog? {
638638 let message = json["message"]
639639 if let id = message["chat_id"].int { // Multichat
640640 if let sMessage = processMessage(message) {
Melk/VKPublicCrap.swift+3−6
@@ -6,8 +6,8 @@
66// Copyright © 2016 Ilya Kos. All rights reserved.
77//
88
9−//import SwiftyVK
10−/*
9+import SwiftyVK
10+
1111let permissions: Set<VK.Scope> = [
1212// .notify,
1313// .friends,
@@ -30,8 +30,7 @@ let permissions: Set<VK.Scope> = [
3030// .offline,
3131// .market,
3232]
33− */
34−let vkAPIVersion = "5.67"
33+let vkAPIVersion = "5.60"
3534let appID = "6097091"
3635
3736let multichatchatId = 2000000000
@@ -39,5 +38,3 @@ let multichatchatId = 2000000000
3938enum Methods {
4039 static let getDialogs = "getDialogs"
4140}
42−
43−let accessKey = "363b0ecf363b0ecf363b0ecf9a3666060c3363b363b0ecf6f6cb5bcd453ddb4d0fadf8a"
Melk/VKServer.swiftdeleted−123
@@ -1,123 +0,0 @@
1−//
2−// VKServer.swift
3−// Melk
4−//
5−// Created by Ilya Kos on 7/12/17.
6−// Copyright © 2017 Ilya Kos. All rights reserved.
7−//
8−
9−import Foundation
10−import Alamofire
11−
12−class VKServer {
13− static func get(photo: Photo, completion: @escaping ((Data) -> ())) {
14− func string(`for` photo: Photo) -> String? {
15− if let ownerID = photo.owner?.id {
16− let id = photo.id
17− var out = "\(ownerID)_\(id)"
18− if let accessKey = photo.accessKey {
19− out.append("_\(accessKey)")
20− }
21− return out
22− }
23− return nil
24− }
25− let params: Parameters = [
26− "photos": string(for: photo)!
27− ]
28− Alamofire.request(url(for: "photos.getById"), parameters: params)
29− .validate().responseData { (response) in
30− switch response.result {
31− case .success(let data):
32− completion(data)
33− case .failure(let error):
34− print(error)
35− }
36− }
37− }
38− static func get(video: Video, completion: @escaping ((Data) -> ())) {
39− func string(`for` video: Video) -> String? {
40− if let ownerID = video.owner?.id {
41− let id = video.id
42− var out = "\(ownerID)_\(id)"
43− if let accessKey = video.accessKey {
44− out.append("_\(accessKey)")
45− }
46− return out
47− }
48− return nil
49− }
50− let params: Parameters = [
51− "videos": string(for: video)!
52− ]
53− Alamofire.request(url(for: "videos.get"), parameters: params)
54− .validate().responseData { (response) in
55− switch response.result {
56− case .success(let data):
57− completion(data)
58− case .failure(let error):
59− print(error)
60− }
61− }
62− }
63− static func get(doc: Document, completion: @escaping ((Data) -> ())) {
64− if let userID = doc.owner?.id {
65− let id = doc.id
66− let params: Parameters = [
67− "docs": "\(userID)_\(id)"
68− ]
69− Alamofire.request(url(for: "docs.getById"), parameters: params)
70− .validate().responseData(completionHandler: { (response) in
71− switch response.result {
72− case .success(let data):
73− completion(data)
74− case .failure(let error):
75− print(error)
76− }
77− })
78− }
79− }
80− static func get(user: User, completion: @escaping ((Data) -> ())) {
81− let id = user.id
82− let params: Parameters = [
83− "user_ids": id,
84− "fields": "photo_100"
85− ]
86− Alamofire.request(url(for: "users.get"), parameters: params)
87− .validate().responseData { (response) in
88− switch response.result {
89− case .success(let data):
90− completion(data)
91− case .failure(let error):
92− print(error)
93− }
94− }
95− }
96− static func get(wallPost: WallPost, completion: @escaping ((Data) -> ())) {
97− if let userID = wallPost.owner?.id {
98− let id = wallPost.id
99− let params: Parameters = [
100− "posts": "\(userID)_\(id)"
101− ]
102− Alamofire.request(url(for: "wall.getById"), parameters: params)
103− .validate().responseData(completionHandler: { (response) in
104− switch response.result {
105− case .success(let data):
106− completion(data)
107− case .failure(let error):
108− print(error)
109− }
110− })
111− }
112− }
113−
114− static func get(wallPostReply: WallPostReply, completion: @escaping ((Data) -> ())) {
115− // TODO: Get wallPostReply
116− }
117−
118−}
119−
120−fileprivate func url(`for` method: String) -> URL {
121− let surl = "https://api.vk.com/method/\(method)?access_token=\(accessKey)&v=\(vkAPIVersion)&lang=0"
122− return URL.init(string: surl)!
123−}
Melk/VkServices.swiftnew file+207
@@ -0,0 +1,207 @@
1+//
2+// VkServices.swift
3+// golos
4+//
5+// Created by Ilya Kos on 7/24/16.
6+// Copyright © 2016 Ilya Kos. All rights reserved.
7+//
8+
9+import UIKit
10+import Alamofire
11+import SwiftyVK
12+
13+// let realm = try! Realm()
14+
15+class VkServices {
16+ class func getDialogs(offset: Int = 0, count: Int = 200, completion: (() -> ())? = nil) { // Messages
17+ VK.API.remote(method: Methods.getDialogs, parameters:
18+ [VK.Arg.offset: String(offset),
19+ VK.Arg.count: String(count)])
20+ .send(onSuccess: { (response) in
21+ if let usersJSON = response[1].array,
22+ let chatUsersJSON = response[2].array,
23+ let dialogs = response[0]["items"].array,
24+ let chatUserInvitersJSON = response[3].array,
25+ let multichatsJSON = response[4].array { // TODO: Catch error from vk
26+ userQueue.async {
27+ let _ = usersJSON.map(VKData.processUser)
28+ let _ = chatUsersJSON.map(VKData.processUser)
29+ let _ = chatUserInvitersJSON.flatMap(VKData.processUser)
30+ let _ = multichatsJSON.map(VKData.processMultichat)
31+ let _ = dialogs.map(VKData.processDialog)
32+ print("DONEZO")
33+ DispatchQueue.main.async {
34+ completion?()
35+ }
36+ }
37+ }
38+ }, onError: { error in
39+ print(error)
40+ }) // TODO: Handle error
41+ }
42+
43+
44+ /// - Parameters:
45+ /// - dialog: in the `200000000` and `-` fomat
46+ /// - count: count
47+ /// - offset: offset
48+ /// - completion: completion handler
49+ class func getMessages(forDialog dialog: DialogID, count: Int = 20, offset: Int = 0, completion: (() -> ())? = nil) {
50+ var params: [VK.Arg: String] = [
51+ VK.Arg.peerId: String(dialog),
52+ VK.Arg.offset: String(offset),
53+ VK.Arg.count: String(count)]
54+ var request = VK.API.Messages.getHistory()
55+ request.add(parameters: params)
56+ request.send(onSuccess: { (response) in
57+ userQueue.async {
58+ realmWrite { _ in
59+ let rDialog = RealmDialog.by(peerID: dialog)
60+ var f = rDialog.value
61+ f <- response["items"].array?.flatMap(VKData.processMessage)
62+ f?.lastReadMessageID = max(response["out_read"].intValue, response["in_read"].intValue) // TODO: Probrably should use seperate things for readin and readout
63+ response["count"].int >>> { rDialog.value?.count.value = $0 }
64+ }
65+ }
66+ }, onError: nil) // TODO: Handle error
67+
68+ completion?()
69+ }
70+
71+ class func send(_ message: Message, to dialog: RealmDialog, completion: (() -> ())? = nil) {
72+ let date = Date()
73+ let time = Int(date.timeIntervalSince1970) * 100
74+ var params: [VK.Arg: String] = [:]
75+ if let d = dialog.value {
76+ switch d {
77+ case let chat as Chat:
78+ params[VK.Arg.peerId] = String(chat.userID)
79+ case let mchat as Multichat:
80+ params[VK.Arg.chatId] = String(mchat.id)
81+ default:
82+ break
83+ }
84+ }
85+ if dialog.dateLastSent == date {
86+ realmWrite({ (_) in
87+ dialog.dateSentNumber += 1
88+ })
89+ } else {
90+ realmWrite({ (_) in
91+ dialog.dateSentNumber = 1
92+ dialog.dateLastSent = date
93+ })
94+ }
95+
96+ var i = 0
97+ func photoUploadRequest() {
98+ if i < message.outPhotos.count {
99+ if let data = UIImagePNGRepresentation(message.outPhotos[i]) {
100+ let request = VK.API.Upload.Photo.toMessage(SwiftyVK.Media.init(imageData: data, type: .PNG))
101+ request.send(onSuccess: { (response) in
102+ if let photo = VKData.processPhoto(response) { // TODO: this probrably shouldnt happen on the main queue
103+ message.attachments.append(RealmMedia(value: Media.photo(photo)))
104+ }
105+ i += 1
106+ photoUploadRequest()
107+ }, onError: nil) // TODO: Handle error
108+ } else {
109+ i += 1
110+ photoUploadRequest()
111+ }
112+ }
113+ }
114+
115+
116+
117+ params[VK.Arg.randomId] = String(time + dialog.dateSentNumber)
118+ params[VK.Arg.message] = String(message.body)
119+ message.geolocation?.geoCoordinates?.coordinate.latitude >>> {params[VK.Arg.lat] = String($0)}
120+ message.geolocation?.geoCoordinates?.coordinate.longitude >>> {params[VK.Arg.long] = String($0)}
121+ var att = ""
122+ var stickerID: Int?
123+ for m in message.attachments {
124+ m.string >>> { att.append("\($0),") }
125+ if stickerID == nil {
126+ if let v = m.value {
127+ switch v {
128+ case .sticker(let s):
129+ stickerID = s.id
130+ default:
131+ break
132+ }
133+ }
134+ }
135+ }
136+ params[VK.Arg.attachments] = att
137+ var fm = ""
138+ for m in message.forwardedMessages {
139+ m.id >>> {fm.append("\($0),")}
140+ }
141+ params[VK.Arg.forwardMessages] = fm
142+ stickerID >>> {params[VK.Arg.stickerId] = String($0)}
143+ VK.API.Messages.send(params).send(onSuccess: { (response) in
144+ if let id = response.int {
145+ realmWrite({ (_) in
146+ message.id = id
147+ dialog.value?.messages <~ message // TODO: Uncomment this
148+ })
149+ }
150+ completion?()
151+ }, onError: nil) // TODO: Handle error
152+ }
153+ class func getMultichat(for id: MultichatID) {
154+ let params: [VK.Arg: String] = [
155+ VK.Arg.chatId: String(id),
156+ VK.Arg.fields: "nickname, screen_name, sex, bdate, city, country, timezone, photo_50, photo_100, photo_200_orig, has_mobile, contacts, education, online, counters, relation, last_seen, status, can_write_private_message, can_see_all_posts, can_post, universities",
157+
158+ ]
159+ VK.API.Messages.getChat(params).send(onSuccess: { (response) in
160+ VKData.processMultichat(response)
161+ }, onError: nil) // TODO: Handle error
162+ }
163+
164+}
165+
166+fileprivate extension RealmMedia {
167+ var string: String? {
168+ if let v = value {
169+ switch v {
170+ case .photo(let p):
171+ if let o = p.owner {
172+ var out = "photo\(o.id)_\(p.id)"
173+ p.accessKey >>> {out.append("_\($0)")}
174+ return out
175+ }
176+ case .video(let p):
177+ if let o = p.owner {
178+ var out = "video\(o.id)_\(p.id)"
179+ p.accessKey >>> {out.append("_\($0)")}
180+ return out
181+ }
182+ case .audio(let p):
183+ if let o = p.owner {
184+ return "audio\(o.id)_\(p.id)"
185+ }
186+ case .doc(let p), .graffiti(let p):
187+ if let o = p.owner {
188+ return "doc\(o.id)_\(p.id)"
189+ }
190+ case .wall(let p):
191+ if let o = p.owner {
192+ return "photo\(o.id)_\(p.id)"
193+ }
194+ case .market(let p):
195+ if let o = p.owner {
196+ return "photo\(o.id)_\(p.id)"
197+ }
198+ default: break
199+ }
200+ }
201+ return nil
202+ }
203+}
204+
205+private func URLFor(method: String) -> String {
206+ return "https://api.vk.com/method/" + method
207+}
README.mddeleted−17
@@ -1,17 +0,0 @@
1−# Melk
2−
3−_Might not work properly with new streaming API. This project was developed while the API was in beta._
4−
5−[![Melk demo](http://img.youtube.com/vi/9SNc0bLDCL0/0.jpg)](http://www.youtube.com/watch?v=9SNc0bLDCL0)
6−
7−При проведении различных мероприятий организаторы довольно часто призывают людей, посещающих эти мероприятия, выложить у себя в соц сети что-нибудь об этом мероприятии, чаще всего под мероприятие даже выделяется отдельный хештег.
8−
9−Для привлечения внимания к хештегу и поощрения его использования можно выводить некоторые из выложенных с хештегом записей туда, где все смогут это увидеть.
10−
11−При проведении больших мероприятий желательно использовать большое количество независимых систем, чтобы если летит что-то одно, все остальное продолжало работать.
12−
13−Полноценный десктопный компьютер для данной цели не нужен, поэтому приложение работает просто на телефоне или планшете.
14−
15−Самый первый хештег или ключевое слово будет крупно показано вместе со всеми записями.
16−
17−После того, как будет нажата кнопка “Present”, записи с основным хештегом будут выводиться на любые подключенные к устройству экраны.