@@ -1,2270 +0,0 @@
1−//
2−// File.swift
3−// golos
4−//
5−// Created by Ilya Kos on 12/12/16.
6−// Copyright © 2016 Ilya Kos. All rights reserved.
7−//
8−
9−import UIKit
10−import RealmSwift
11−import Alamofire
12−import CoreLocation
13−import Nuke
14−import SwiftyJSON
15−//import SwiftyVK
16−
17−
18−typealias Token = String
19−typealias UserID = Int
20−typealias MessageID = Int
21−typealias MultichatID = Int
22−
23−class RealmPhoto: Object {
24−
25− convenience init(surl: String, id: String) {
26− self.init()
27− self.imageSURL = surl
28− self.id = id
29− }
30−
31− @objc dynamic var id: String = ""
32− var imageURL: URL? {
33− get {
34− return imageSURL =>> {URL(string: $0)}
35− }
36− set {
37− imageSURL = newValue?.absoluteString
38− }
39− }
40− @objc dynamic var imageSURL: String? {
41− didSet {
42− if oldValue != imageSURL {
43− localImageSURL = nil
44− }
45− }
46− }
47− @objc private dynamic var localImageSURL: String? {
48− didSet {
49− if oldValue != localImageSURL {
50− imageCache = nil
51− }
52− }
53− }
54− private var imageCache: UIImage?
55−
56− convenience init(id: String, surl: String?) {
57− self.init()
58− self.id = id
59− self.imageSURL = surl
60− }
61−
62− class func by(_ id: String, surl: String?) -> RealmPhoto {
63− do {
64− let realm = try Realm()
65− if let ob = realm.object(ofType: RealmPhoto.self, forPrimaryKey: id) {
66− if realm.isInWriteTransaction {
67− surl =>> {ob.imageSURL = $0}
68− } else {
69− try? realm.write {
70− surl =>> {ob.imageSURL = $0}
71− }
72− }
73− return ob
74− } else {
75− let ob = RealmPhoto(id: id, surl: surl)
76− if realm.isInWriteTransaction {
77− realm.add(ob)
78− } else {
79− try? realm.write {
80− realm.add(ob)
81− }
82− }
83− return ob
84− }
85− } catch {
86− let ob = RealmPhoto(id: id, surl: surl)
87− return ob
88− }
89− }
90−
91− override static func primaryKey() -> String? {
92− return "id"
93− }
94−
95− override static func ignoredProperties() -> [String] {
96− return ["imageURL", "imageCache", "completions", "request"]
97− }
98−
99− var completions: [((() -> ()), RealmPhotoToken)] = []
100− var views: [(UIImageView?, RealmPhotoToken)] = []
101− var request: DataRequest?
102−
103− @discardableResult func load(into view: UIImageView, completion: (() -> ())? = nil, error errorClosure: (() -> ())? = nil) -> RealmPhotoToken {
104−
105− let token = RealmPhotoToken()
106−
107− func getFromServer() {
108− if request == nil {
109− let surl = "\(id).png"
110− if let url = imageURL {
111− print("getting from network")
112− request = Alamofire.request(url, method: .get).validate().responseData(queue: userQueue) { (responce) in
113− self.request = nil
114− switch responce.result {
115− case .success(let data):
116− UIImage(data: data) >>> {image in
117− write(cache: UIImagePNGRepresentation(image), withName: surl) {
118− realmWrite({ (realm) in
119− realm.object(ofType: RealmPhoto.self, forPrimaryKey: self.id)?.localImageSURL = surl
120− })
121− }
122− self.imageCache = image
123− DispatchQueue.main.async {
124− if token.isValid {
125− self.views.map { if $0.1.isValid {$0.0?.image = image} }
126− self.completions.map { if $0.1.isValid { $0.0() } }
127− self.completions = []
128− }
129− }
130− }
131− case .failure(let error):
132− errorClosure?()
133− // TODO: Error handling
134− break
135− }
136− }
137− }
138− }
139− }
140−
141− if let surl = localImageSURL, // TODO: Should probrably get thing from server ???
142− let url = url(forName: surl) {
143− Nuke.loadImage(with: url, into: view) { [weak view] (response, fromMemory) in
144− switch response {
145− case .fulfilled(let image):
146− if token.isValid {
147− view?.image = image
148− completion?()
149− }
150− case .rejected(let error): // TODO: Handle error?
151− completion >>> {self.completions.append(($0, token))}
152− self.views.append((view, token))
153− getFromServer()
154− }
155− }
156− } else {
157− completion >>> {self.completions.append(($0, token))}
158− self.views.append((view, token))
159− getFromServer()
160− }
161−
162− return token
163− }
164−
165− // func image(_ completion: @escaping ((UIImage?) -> ())) {
166− // print(id)
167− // let surl = "\(id).png"
168− // if imageCache != nil {
169− // print("we have caching!")
170− // }
171− // imageCache = imageCache ?? (localImageSURL =>> getLocalImage) // TODO: imageCache always seems to be nil... ie always loading from disk for some reason
172− // if let sImage = imageCache {
173− // DispatchQueue.main.async { completion(sImage) }
174− // } else if let url = imageURL {
175− // print("getting from network")
176− // Alamofire.request(url, method: .get).validate().responseData(queue: userQueue) { (responce) in
177− // switch responce.result {
178− // case .success(let data):
179− // UIImage(data: data) >>> {image in
180− // write(cache: UIImagePNGRepresentation(image), withName: surl) {
181− // DispatchQueue.main.async {
182− // do {
183− // let realm = try Realm()
184− // if !realm.isInWriteTransaction {
185− // try realm.write {
186− // self.localImageSURL = surl
187− // }
188− // } else {
189− // self.localImageSURL = surl
190− // }
191− // } catch { }
192− // }
193− // }
194− // self.imageCache = image
195− // DispatchQueue.main.async {completion(image)}
196− // }
197− // case .failure(let error):
198− // // TODO: Error handling
199− // break
200− // }
201− // }.resume()
202− // }
203− // }
204−}
205−
206−public class RealmPhotoToken {
207− public func cancel() {
208− isValid = false
209− }
210− fileprivate var isValid = true
211−}
212−
213−
214−class User: Object {
215− @objc dynamic var id: UserID = 0
216− @objc dynamic var firstName: String?
217− @objc dynamic var lastName: String?
218− var deactivated: Deactivated? {
219− get {
220− return deactivatedStr =>> {Deactivated.init(rawValue: $0)}
221− }
222− set {
223− deactivatedStr = newValue >>> {$0.rawValue}
224− }
225− }
226− @objc private dynamic var deactivatedStr: String?
227−
228− @objc dynamic var about: String?
229− @objc dynamic var birthday: Date?
230− let blacklisted = RealmOptional<Bool>()
231− let canSendFriendRequest = RealmOptional<Bool>()
232− let canSendPrivateMessage = RealmOptional<Bool>()
233− let mutualFriendCount = RealmOptional<Int>()
234− // TODO: var connections:
235− @objc dynamic var mobilePhone: String?
236− @objc dynamic var homePhone: String?
237− // TODO: var exports
238− var friendStatus: FriendStatus? {
239− get {
240− return friendStatusInt.value =>> {FriendStatus(rawValue: $0)}
241− }
242− set {
243− friendStatusInt.value = newValue >>> {$0.rawValue}
244− }
245− }
246− private let friendStatusInt = RealmOptional<Int>()
247− let online = RealmOptional<Bool>()
248− @objc dynamic var avatar: RealmPhoto?
249− var avatarID: String {
250− return "user\(id)avatar"
251− }
252− @objc dynamic var photo: RealmPhoto?
253− var photoID: String {
254− return "user\(id)photo"
255− }
256− var site: URL? {
257− get {
258− return siteSURL =>> {URL.init(string: $0)}
259− }
260− set {
261− siteSURL = newValue >>> {$0.absoluteString}
262− }
263− }
264− @objc dynamic var siteSURL: String?
265− @objc dynamic var status: String?
266− @objc dynamic var lastSeen: Date?
267− // dynamic var lastUpdated: Date = Date()
268− let friendCount = RealmOptional<Int>()
269−
270− convenience init(id: UserID, firstName: String, lastName: String) {
271− self.init()
272− self.id = id
273− self.firstName = firstName
274− self.lastName = lastName
275− // self.lastUpdated = Date()
276− }
277− class func by(id: UserID) -> User {
278− let realm = try! Realm()
279− if let us = realm.object(ofType: User.self, forPrimaryKey: id) {
280− return us
281− } else {
282− let us = User()
283− us.id = id
284− if realm.isInWriteTransaction {
285− realm.add(us)
286− } else {
287− try? realm.write {
288− realm.add(us)
289−
290− }
291− }
292− return us
293− }
294− }
295−
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−// }
308− 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)
313− }
314− }
315− }
316−
317−
318− override static func primaryKey() -> String? {
319− return "id"
320− }
321−
322− override static func ignoredProperties() -> [String] {
323− return ["site", "photoID", "avatarID"]
324− }
325− // func update() { lastUpdated = Date() }
326−
327− // MARK: Hashable override
328−
329− override var hashValue: Int {
330− return id
331− }
332−}
333−
334−class Geolocation: Object {
335− var geoCoordinates: CLLocation? {
336− get {
337− if let long = long.value, let latt = latt.value {
338− return CLLocation(latitude: latt, longitude: long)
339− }
340− return nil
341− }
342− set {
343− if let latt = newValue?.coordinate.latitude,
344− let long = newValue?.coordinate.longitude {
345− self.latt.value = latt
346− self.long.value = long
347− } else {
348− self.long.value = nil
349− self.latt.value = nil
350− }
351− }
352− }
353− private let latt = RealmOptional<Double>()
354− private let long = RealmOptional<Double>()
355− let id = RealmOptional<Int>()
356− @objc dynamic var title: String?
357− @objc dynamic var image: RealmPhoto?
358− var imageID: String {
359− return "geo_lat\(latt.value ?? 0)_long\(long.value ?? 0)image"
360− }
361− var city: String?
362− var country: String?
363−
364− override static func ignoredProperties() -> [String] {
365− return ["geoCoordinates", "imageID"]
366− }
367− convenience init(long: Double, latt: Double) {
368− self.init()
369− self.long.value = long
370− self.latt.value = latt
371− }
372−
373−}
374−
375−class GenericMessage: Object {
376− @objc dynamic var date = Date() //
377− @objc dynamic var body = "" //
378− @objc dynamic var user: User?
379−
380− var outPhotos: [UIImage] = [] // TODO: ~
381−
382− @objc dynamic var geolocation: Geolocation?
383−
384− let attachments = List<RealmMedia>()
385− let forwardedMessages = List<RealmForwardedMessage>()
386− //let sentMessageId: MessageID? I DONT KNOW WHY I PUT THIS HERE
387−
388− // convenience init(body: String) {
389− // self.init()
390− // self.body = body
391− // self.out.value = true
392− // }
393− // convenience init(image: UIImage) {
394− // self.init()
395− // self.outPhotos.append(image)
396− // }
397− override static func ignoredProperties() -> [String] {
398− return ["outPhotos"]
399− }
400−}
401−
402−class Message: GenericMessage, Comparable, SortedArrayItem {
403− @objc dynamic var id = 0
404− let randomID = RealmOptional<MessageID>()
405− @objc dynamic var read = false
406− @objc dynamic var replied = false
407− @objc dynamic var important = false
408− @objc dynamic var deleted = false
409−
410− func equal(to message: Message) -> Bool {
411− // print("\(lhs.id.value) \(rhs.id.value) \(lhs.id.value == rhs.id.value)")
412− if let a = self.randomID.value,
413− let b = message.randomID.value {
414− if a == b {
415− return true
416− }
417− }
418− return self.id == message.id
419− }
420− internal func greater(than message: Message) -> Bool {
421− return self.id < message.id
422− }
423−
424− static func ==(lhs: Message, rhs: Message) -> Bool {
425− print("\(lhs.id) \(rhs.id) \(lhs.id == rhs.id)")
426− return lhs.id == rhs.id
427− }
428−
429− @objc dynamic var out = false
430−
431− // Multichat stuff
432−
433− @objc dynamic var photoSURL: String?
434− let chatID = RealmOptional<MultichatID>()
435− @objc private dynamic var serviceMessageString: String?
436− private var serviceMessageUser: User?
437− private let serviceMessage = RealmOptional<Int>()
438−
439− var action: ServiceMessageAction? {
440− get {
441− func getUser() -> ServiceMessageUser? {
442− if let user = self.serviceMessageUser {
443− return .user(user)
444− } else if let email = self.serviceMessageString {
445− return .email(email)
446− } else {
447− return nil
448− }
449− }
450−
451− return serviceMessage.value =>> { service in
452− switch service {
453− case 0:
454− return .photoUpdate
455− case 1:
456− return .photoRemove
457− case 2:
458− return self.serviceMessageString >>> { .create($0) }
459− case 3:
460− return self.serviceMessageString >>> { .titleUpdate($0) }
461− case 4:
462− return getUser() >>> { .inviteUser($0) }
463− case 5:
464− return getUser() >>> { .kickUser($0) }
465− default:
466− return nil
467− }
468− }
469− }
470− set {
471− func set(user: ServiceMessageUser) {
472− switch user {
473− case .user(let use):
474− self.serviceMessageUser = use
475− case .email(let str):
476− self.serviceMessageString = str
477− }
478− }
479−
480− serviceMessageString = nil
481− serviceMessageUser = nil
482− serviceMessage.value = newValue >>> { new in
483− switch new {
484− case .photoUpdate:
485− return 0
486− case .photoRemove:
487− return 1
488− case .create(let str):
489− self.serviceMessageString = str
490− return 2
491− case .titleUpdate(let str):
492− self.serviceMessageString = str
493− return 3
494− case .inviteUser(let user):
495− set(user: user)
496− return 4
497− case .kickUser(let user):
498− set(user: user)
499− return 5
500− }
501− }
502− }
503− }
504−
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−// }
518−
519− class func by(id: MessageID) -> Message {
520− let realm = try! Realm()
521− if let us = realm.object(ofType: Message.self, forPrimaryKey: id) {
522− return us
523− } else {
524− let us = Message()
525− us.id = id
526− realmWrite({ (_) in
527− realm.add(us)
528− })
529− return us
530− }
531− }
532−
533− override static func primaryKey() -> String? {
534− return "id"
535− }
536−}
537−//func ==(lhs: Message, rhs: Message) -> Bool {
538−// print("\(lhs.id.value) \(rhs.id.value) \(lhs.id.value == rhs.id.value)")
539−// return lhs.id.value == rhs.id.value
540−//}
541−func <(lhs: Message, rhs: Message) -> Bool {
542− return lhs.id < rhs.id
543−}
544−
545−enum forwardedMessage {
546− case genericMessage(GenericMessage)
547− case message(Message)
548−}
549−
550−class RealmForwardedMessage: Object {
551− var value: forwardedMessage? {
552− get {
553− if let gm = genericMessage {
554− return .genericMessage(gm)
555− } else if let m = message {
556− return .message(m)
557− } else {
558− return nil
559− }
560− }
561− set {
562− realmWrite { _ in
563− if let fm = newValue {
564− switch fm {
565− case .genericMessage(let gm):
566− genericMessage = gm
567− message = nil
568− case .message(let m):
569− genericMessage = nil
570− message = m
571− }
572− } else {
573− message = nil
574− genericMessage = nil
575− }
576− }
577− }
578− }
579− @objc private dynamic var genericMessage: GenericMessage?
580− @objc private dynamic var message: Message?
581−
582− var id: MessageID? {
583− if let m = message {
584− return m.id
585− } else {
586− return nil
587− }
588− }
589−
590− convenience init(value: forwardedMessage) {
591− self.init()
592− self.value = value
593− }
594−
595− override static func ignoredProperties() -> [String] {
596− return ["value"]
597− }
598−}
599−
600−//struct Geolocation {
601−// var coordinates: CLLocation
602−// var title: String?
603−// var imageURL: URL? {
604−// get {
605−// return imageSURL =>> {URL.init(string: $0)}
606−// }
607−// set {
608−// imageSURL = newValue?.absoluteString
609−// }
610−// }
611−// var imageSURL: String?
612−// // func image(completion: ((UIImage) -> ())) {
613−// // imageFunc =>> {$0(completion)}
614−// // }
615−// var image: (@escaping ((UIImage) -> ()) -> ())?
616−// var city: String?
617−// var country: String?
618−// init(coordinates: CLLocation, title: String?, imageSURL: String?, image: (@escaping ((UIImage) -> ()) -> ()), city: String?, country: String?) {
619−// self.coordinates = coordinates
620−// self.title = title
621−// self.imageSURL = imageSURL
622−// self.image = image
623−// self.city = city
624−// self.country = country
625−// }
626−//}
627−typealias GeolocationID = Int
628−
629−enum Deactivated: String {
630− case banned = "banned"
631− case deleted = "deleted"
632− case normal = "normal"
633−}
634−
635−enum FriendStatus: Int {
636− case notFriends = 0
637− case requestSent
638− case requestRecieved
639− case fiend
640−}
641−
642−enum MessageReadState: Int {
643− case read = 0
644− case notRead
645−}
646−enum MessageSendState: Int {
647− case received = 0
648− case sent
649−}
650−
651−enum MultichatNotificationSetting {
652− case sound
653− case disabled_until
654−}
655−
656−enum ServiceMessageAction {
657− case photoUpdate // 0
658− case photoRemove // 1
659− case create(String) // 2
660− case titleUpdate(String) // 3
661− case inviteUser(ServiceMessageUser) // 4
662− case kickUser(ServiceMessageUser) // 5
663−}
664−
665−enum ServiceMessageUser {
666− case user(User)
667− case email(String)
668−}
669−
670−typealias MessageChunkID = String
671−class MessageChunk: Object { // message ids go down
672− subscript(index: Int) -> Message {
673− return messages[index]
674− }
675−
676− @objc dynamic var id: MessageChunkID = ""
677−
678− fileprivate let messages = List<Message>()
679−
680− var firstMessage: Message? {
681− return messages.first
682− }
683−
684− var lastMessage: Message? {
685− return messages.last
686− }
687−
688− var firstID: MessageID? {
689− return firstMessage?.id
690− }
691−
692− var lastID: MessageID? {
693− return lastMessage?.id
694− }
695−
696− var count: Int {
697− return messages.count
698− }
699−
700− fileprivate func append(message: Message?) {
701− message >>> {messages.append($0)}
702− }
703−
704− override static func primaryKey() -> String? {
705− return "id"
706− }
707−
708− override static func ignoredProperties() -> [String] {
709− return ["firstMessage", "lastMessage", "firstID", "lastID", "count"]
710− }
711−}
712−
713−func +=(lhs: MessageChunk, rhs: MessageChunk) {
714− lhs.messages.append(objectsIn: rhs.messages)
715−}
716−
717−/// Returns: true if added. false if was already in list
718−func <~(lhs: MessageChunk?, rhs: Message?) -> Bool {
719− var out: Bool = false
720− realmWrite { (_) in
721− out = lhs?.messages <~ rhs
722− }
723− return out
724−}
725−/// Returns: Indexes of added items
726−func <-(lhs: MessageChunk?, rhs: [Message?]?) -> [Int] {
727− var out: [Int] = []
728− realmWrite { (_) in
729− out = lhs?.messages <- rhs
730− }
731− return out
732−}
733−/// Returns: Indexes of added items
734−func <-(lhs: MessageChunk?, rhs: MessageChunk?) -> [Int] {
735− var out: [Int] = []
736− realmWrite { (_) in
737− out = lhs?.messages <- rhs?.messages
738− }
739− return out
740−}
741−
742−enum MessageEntry {
743− case message(Message)
744− case spacer
745−}
746−
747−typealias MessagesID = Int
748−class Messages: Object {
749− subscript(ind: Int) -> MessageEntry? {
750− assert(ind >= 0, "index out of bounds")
751− if ind >= count || ind < 0 {
752− return nil
753− }
754− var index = ind
755− var i = 0
756− while messageChunks[i].count < index {
757− index -= messageChunks[i].count + 1
758− i += 1
759− }
760− if index == messageChunks[i].count {
761− return .spacer
762− } else {
763− return .message(messageChunks[i][index])
764− }
765− }
766−
767− @objc dynamic var id: MessagesID = 0
768−
769− @objc fileprivate dynamic var lastChunkID = 0
770−
771− var endIndex: Int {
772− return messageChunks.endIndex
773− }
774−
775− var first: Message? {
776− return messageChunks.first?.firstMessage
777− }
778−
779− func count(upToChunk index: Int) -> Int {
780− var n = 0
781− for i in 0..<index {
782− n += messageChunks[i].count + 1
783− }
784− return n
785− }
786−
787− public var count: Int {
788− var n = messageChunks.count - 1
789− for chunk in messageChunks {
790− n += chunk.count
791− }
792− return n
793− }
794−
795− fileprivate let messageChunks = List<MessageChunk>()
796−
797− public var chunks: List<MessageChunk> {
798− return messageChunks
799− }
800−
801− fileprivate enum ChunkIndex {
802− case inside(Int)
803− case after(Int)
804− case beforeFirst
805− }
806−
807− fileprivate func createChunk(at index: Int = 0) -> MessageChunk {
808− let chunk = MessageChunk()
809− realmWrite { (realm) in
810− chunk.id = "\(id)_\(lastChunkID)"
811− lastChunkID += 1
812− realm.add(chunk)
813− messageChunks.insert(chunk, at: index)
814− }
815− return chunk
816− }
817−
818− /// Return nil if there are no chunks
819− fileprivate func chunkIndex(of message: Message) -> ChunkIndex? {
820− if messageChunks.count == 0 {
821− return nil
822− }
823− if let first = messageChunks.first?.firstMessage {
824− if first.greater(than: message) {
825− return .beforeFirst
826− }
827− }
828− for (i, chunk) in messageChunks.enumerated() {
829− if let lastMessage = chunk.lastMessage { // It should never be nil since a chunk is never empty
830− if !message.greater(than: lastMessage) { // [ ... | ()] [...] ...
831− if i == 0 {
832− return .inside(i)
833− } else {
834− if let firstMessage = chunk.firstMessage { // It should never be nil since a chunk is never empty
835− if message.greater(than: firstMessage) || message.equal(to: firstMessage) {
836− return .inside(i)
837− } else {
838− return .after(i-1)
839− }
840− }
841− }
842− }
843− }
844− }
845− return .after(endIndex-1)
846− }
847−
848−
849− override static func primaryKey() -> String? {
850− return "id"
851− }
852−
853− override static func ignoredProperties() -> [String] {
854− return ["endIndex"]
855− }
856−
857− class func by(id: MessagesID) -> Messages {
858− let realm = try! Realm()
859− if let us = realm.object(ofType: Messages.self, forPrimaryKey: id) {
860− return us
861− } else {
862− let us = Messages()
863− us.id = id
864− realm.add(us)
865− return us
866− }
867− }
868−
869− // MARK: Messages obesrver
870−
871− static let notificationName: Notification.Name = Notification.Name(rawValue: "MessagesWereModifiedNotificationName")
872−
873− enum Changes {
874− case added
875− case modified
876− case deleted
877− }
878−}
879−
880−
881−
882−/// Returns: true if added. false if was already in list
883−func <~(lhs: Messages?, rhs: Message?) -> Bool {
884− var out: Bool = false
885− if let lhs = lhs,
886− let rhs = rhs {
887− realmWrite { (_) in
888− if let index = lhs.chunkIndex(of: rhs) {
889− switch index {
890− case .after(let i):
891− lhs.messageChunks[i].append(message: rhs)
892− out = true
893− case .inside(let i):
894− out = lhs.messageChunks[i] <~ rhs
895− case .beforeFirst:
896− out = lhs.createChunk(at: 0) <~ rhs
897− }
898− } else {
899− out = lhs.createChunk() <~ rhs
900− }
901− }
902− }
903− return out
904−}
905−/// Only accepts a list of SEQUENTIAL messages. Will silently break if not passed sequentially.
906−/// Returns: Indexes of added items
907−func <-(lhs: Messages?, rhs: [Message?]?) /*-> [Int]*/ {
908− print(rhs)
909− print(lhs)
910− if let lhs = lhs,
911− let rhs = rhs?.flatMap({$0}),
912− let first = rhs.first,
913− let last = rhs.last {
914−
915− var deleted: [Int] = []
916− var modified: [Int] = []
917− var added: [Int] = []
918− if let startI = lhs.chunkIndex(of: first),
919− let endI = lhs.chunkIndex(of: last) {
920− var start: Int!
921− var end: Int!
922− print("\t", startI, endI)
923− switch startI {
924− case .inside(let i):
925− start = i
926− case .after(let i):
927− start = i + 1
928− case .beforeFirst:
929− start = -1
930− }
931− switch endI {
932− case .after(let i):
933− end = i
934− case .inside(let i):
935− end = i
936− case .beforeFirst:
937− end = -1
938− }
939−
940− if start < end {
941− print(start, end)
942− start = max(start, 0)
943− var spacerIndexes = (start+1...end).map({lhs.count(upToChunk: $0) - 1})
944− // deleted += spacerIndexes
945− let count = lhs.count(upToChunk: start)
946− var dIndex = 0
947− for i in 0..<spacerIndexes.count {
948− spacerIndexes[i] -= dIndex
949− deleted.append(spacerIndexes[i])
950− spacerIndexes[i] -= count
951− dIndex += 1
952− }
953− var addedMs: [Int]!
954− realmWriteWithCompletion { realm, completion in
955− for x in start+1...end {
956− print(lhs.chunks.count, x)
957− lhs.chunks[start] += lhs.chunks[start+1]
958− realm.delete(lhs.chunks[start+1])
959− // lhs.chunks.remove(objectAtIndex: start+1)
960− }
961− let chunk = lhs.chunks[start]
962− addedMs = chunk <- rhs
963−
964− addedMs.map {$0 + count}
965− added += addedMs
966−
967− completion {
968− print("after notification", lhs.chunks)
969− NotificationCenter.default.post(name: Messages.notificationName,
970− object: lhs.id,
971− userInfo: [Messages.Changes.added: added,
972− Messages.Changes.modified: modified,
973− Messages.Changes.deleted: deleted])
974− }
975− }
976− } else { // within one
977− assert(start == end, "start index is larger than end index!")
978− realmWriteWithCompletion { _, completion in
979− if start == -1 {
980− added += lhs.createChunk(at: 0) <- rhs
981− added.append(0) // IDK o[]o[]o []o[]o
982− } else {
983− added += (lhs.messageChunks[start] <- rhs).map {$0 + lhs.count(upToChunk: start)}
984− }
985− completion {
986− NotificationCenter.default.post(name: Messages.notificationName,
987− object: lhs.id,
988− userInfo: [Messages.Changes.added: added,
989− Messages.Changes.modified: modified,
990− Messages.Changes.deleted: deleted])
991− }
992− }
993− }
994− } else { // empty
995− realmWriteWithCompletion { _, completion in
996− added += lhs.createChunk() <- rhs
997− completion {
998− NotificationCenter.default.post(name: Messages.notificationName,
999− object: lhs.id,
1000− userInfo: [Messages.Changes.added: added,
1001− Messages.Changes.modified: modified,
1002− Messages.Changes.deleted: deleted])
1003− }
1004− }
1005− }
1006− print(lhs)
1007− print(added)
1008− print(deleted)
1009− }
1010−}
1011−
1012−enum Media {
1013− case photo(Photo)
1014− case video(Video)
1015− case audio(Audio)
1016− case doc(Document)
1017− case wall(WallPost)
1018− case wallReply(WallPostReply)
1019− case sticker(Sticker)
1020− case link(Link)
1021− case gift(Gift)
1022− case market(Market)
1023− case marketAlbum(MarketAlbum)
1024− case graffiti(Document)
1025− case note(Note)
1026− case poll(Poll)
1027− case album(PhotoAlbum)
1028− var realm: RealmMedia {
1029− return RealmMedia(value: self)
1030− }
1031−}
1032−
1033−class RealmMedia: Object {
1034− @objc private dynamic var photo: Photo?
1035− @objc private dynamic var video: Video?
1036− @objc private dynamic var audio: Audio?
1037− @objc private dynamic var doc: Document?
1038− @objc private dynamic var wall: WallPost?
1039− @objc private dynamic var wallReply: WallPostReply?
1040− @objc private dynamic var sticker: Sticker?
1041− @objc private dynamic var link: Link?
1042− @objc private dynamic var gift: Gift?
1043− @objc private dynamic var market: Market?
1044− @objc private dynamic var marketAlbum: MarketAlbum?
1045− @objc private dynamic var graffiti: Document?
1046− @objc private dynamic var note: Note?
1047− @objc private dynamic var poll: Poll?
1048− @objc private dynamic var album: PhotoAlbum?
1049−
1050− var value: Media? {
1051− get {
1052− if let sureThing = self.photo { return .photo(sureThing) }
1053− if let sureThing = self.video { return .video(sureThing) }
1054− if let sureThing = self.audio { return .audio(sureThing) }
1055− if let sureThing = self.doc { return .doc(sureThing) }
1056− if let sureThing = self.wall { return .wall(sureThing) }
1057− if let sureThing = self.wallReply { return .wallReply(sureThing) }
1058− if let sureThing = self.sticker { return .sticker(sureThing) }
1059− if let sureThing = self.link { return .link(sureThing) }
1060− if let sureThing = self.gift { return .gift(sureThing) }
1061− if let sureThing = self.market { return .market(sureThing) }
1062− if let sureThing = self.marketAlbum { return .marketAlbum(sureThing) }
1063− if let sureThing = self.graffiti { return .graffiti(sureThing) }
1064− if let sureThing = self.note { return .note(sureThing) }
1065− if let sureThing = self.poll { return .poll(sureThing) }
1066− if let sureThing = self.album { return .album(sureThing) }
1067− return nil
1068− }
1069− set {
1070−
1071− photo = nil
1072− video = nil
1073− audio = nil
1074− doc = nil
1075− wall = nil
1076− wallReply = nil
1077− sticker = nil
1078− link = nil
1079− gift = nil
1080− market = nil
1081− marketAlbum = nil
1082− graffiti = nil
1083− note = nil
1084− poll = nil
1085− album = nil
1086−
1087− if let val = newValue {
1088− switch val {
1089− case .photo(let foo): photo = foo
1090− case .video(let foo): video = foo
1091− case .audio(let foo): audio = foo
1092− case .doc(let foo): doc = foo
1093− case .wall(let foo): wall = foo
1094− case .wallReply(let foo): wallReply = foo
1095− case .sticker(let foo): sticker = foo
1096− case .link(let foo): link = foo
1097− case .gift(let foo): gift = foo
1098− case .market(let foo): market = foo
1099− case .marketAlbum(let foo): marketAlbum = foo
1100− case .graffiti(let foo): graffiti = foo
1101− case .note(let foo): note = foo
1102− case .poll(let foo): poll = foo
1103− case .album(let foo): album = foo
1104− }
1105− }
1106− }
1107− }
1108− convenience init(value: Media) {
1109− self.init()
1110− self.value = value
1111− }
1112−}
1113−
1114−class Poll: Object {
1115− @objc dynamic var id: PollID = 0
1116− @objc dynamic var owner: User?
1117− @objc dynamic var date: Date?
1118− @objc dynamic var question: String?
1119− let votes = RealmOptional<Int>()
1120− let answerID = RealmOptional<PollAnswerID>()
1121− let answers = List<PollAnswer>()
1122− convenience init(id: PollID, owner: User, date: Date, question: String, votes: Int) {
1123− self.init()
1124− self.id = id
1125− self.owner = owner
1126− self.date = date
1127− self.question = question
1128− self.votes.value = votes
1129− // self.answerID.value = answerID
1130− }
1131− class func by(id: PollID) -> Poll {
1132− let realm = try! Realm()
1133− if let us = realm.object(ofType: Poll.self, forPrimaryKey: id) {
1134− return us
1135− } else {
1136− let us = Poll()
1137− us.id = id
1138− realm.add(us)
1139− return us
1140− }
1141− }
1142−
1143− override class func primaryKey() -> String? {
1144− return "id"
1145− }
1146−}
1147−typealias PollID = Int
1148−
1149−class PollAnswer: Object {
1150− @objc dynamic var id: PollAnswerID = 0
1151− @objc dynamic var body: String = ""
1152− @objc dynamic var votes: Int = 0
1153− @objc dynamic var rating: Int = 0
1154−
1155− convenience init(id: PollAnswerID, body: String, votes: Int, rating: Int) {
1156− self.init()
1157− self.id = id
1158− self.body = body
1159− self.votes = votes
1160− self.rating = rating
1161− }
1162−}
1163−typealias PollAnswerID = Int
1164−
1165−class Note: Object {
1166− @objc dynamic var id: NoteID = 0
1167− @objc dynamic var owner: User?
1168− @objc dynamic var title: String?
1169− @objc dynamic var body: String?
1170− @objc dynamic var date: Date?
1171− var url: URL? {
1172− get {
1173− return surl =>> {URL(string: $0)}
1174− }
1175− set {
1176− surl = newValue >>> {$0.absoluteString}
1177− }
1178− }
1179− @objc dynamic var surl: String?
1180− let commentCount = RealmOptional<Int>()
1181− convenience init(id: NoteID, owner: User, title: String, body: String, date: Date, url: URL, commentCount: Int) {
1182− self.init()
1183− self.id = id
1184− self.owner = owner
1185− self.title = title
1186− self.body = body
1187− self.date = date
1188− self.url = url
1189− self.commentCount.value = commentCount
1190− }
1191− class func by(id: NoteID) -> Note {
1192− let realm = try! Realm()
1193− if let us = realm.object(ofType: Note.self, forPrimaryKey: id) {
1194− return us
1195− } else {
1196− let us = Note()
1197− us.id = id
1198− realm.add(us)
1199− return us
1200− }
1201− }
1202− override class func ignoredProperties() -> [String] {
1203− return ["url"]
1204− }
1205−
1206− override class func primaryKey() -> String? {
1207− return "id"
1208− }
1209−}
1210−typealias NoteID = Int
1211−
1212−typealias GraffitiID = Int
1213−class Graffiti: Document {
1214−} // Use document.image ?
1215−
1216−class Photo: Object {
1217− @objc dynamic var id: PhotoID = 0
1218− @objc dynamic var owner: User?
1219− @objc dynamic var date: Date?
1220− @objc dynamic var thumbnail: RealmPhoto?
1221− var thumbnailID: String {
1222− return "photo\(id)thumbnail"
1223− }
1224− @objc dynamic var image: RealmPhoto?
1225− var imageID: String {
1226− return "photo\(id)image"
1227− }
1228− let width = RealmOptional<Int>()
1229− let height = RealmOptional<Int>()
1230− @objc dynamic var accessKey: Key?
1231−
1232− convenience init(id: PhotoID, owner: User, date: Date){
1233− self.init()
1234− self.id = id
1235− self.owner = owner
1236− self.date = date
1237− }
1238−
1239− class func by(id: PhotoID) -> Photo {
1240− let realm = try! Realm()
1241− if let us = realm.object(ofType: Photo.self, forPrimaryKey: id) {
1242− return us
1243− } else {
1244− let us = Photo()
1245− us.id = id
1246− realm.add(us)
1247− return us
1248− }
1249− }
1250−
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−// }
1271− 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)
1276− }
1277− }
1278− }
1279−
1280− override class func primaryKey() -> String? {
1281− return "id"
1282− }
1283−
1284− override static func ignoredProperties() -> [String] {
1285− return ["thumbnailID", "imageID"]
1286− }
1287−}
1288−
1289−class PhotoAlbum: Object {
1290− @objc dynamic var id: PhotoAlbumID = 0
1291− @objc dynamic var thumb: Photo?
1292− @objc dynamic var owner: User?
1293− @objc dynamic var title: String?
1294− @objc dynamic var albumDescription: String?
1295− @objc dynamic var dateCreated: Date?
1296− @objc dynamic var dateUpdated: Date?
1297− let count = RealmOptional<Int>()
1298− let photos = List<Photo>()
1299− convenience init(id: PhotoAlbumID) {
1300− self.init()
1301− self.id = id
1302− }
1303−
1304− override class func primaryKey() -> String? {
1305− return "id"
1306− }
1307− class func by(id: PhotoAlbumID) -> PhotoAlbum {
1308− let realm = try! Realm()
1309− if let us = realm.object(ofType: PhotoAlbum.self, forPrimaryKey: id) {
1310− return us
1311− } else {
1312− let us = PhotoAlbum()
1313− us.id = id
1314− realm.add(us)
1315− return us
1316− }
1317− }
1318−
1319−
1320− // init(id: PhotoAlbumID, thumbID: PhotoID, ownerID: UserID, title: String, dateCreated: Date, dateUpdated: Date, count: Int) {
1321− // self.id = id
1322− // self.thumbID = thumbID
1323− // self.ownerID = ownerID
1324− // self.title = title
1325− // self.dateCreated = dateCreated
1326− // self.dateUpdated = dateUpdated
1327− // self.count = count
1328− // }
1329−
1330−}
1331−typealias PhotoID = Int
1332−typealias PhotoAlbumID = Int
1333−typealias Key = String
1334−
1335−class WallPost: Object {
1336− @objc dynamic var id: Int = 0
1337− @objc dynamic var owner: User?
1338− @objc dynamic var creator: User?
1339− @objc dynamic var date: Date?
1340− @objc dynamic var body: String?
1341− let commentCount = RealmOptional<Int>()
1342− let canPostComment = RealmOptional<Bool>()
1343− let likeCount = RealmOptional<Int>()
1344− @objc dynamic var liked: Bool = false
1345− let canLike = RealmOptional<Bool>()
1346− let repostCount = RealmOptional<Int>()
1347− let canDelete = RealmOptional<Bool>()
1348− let didRepost = RealmOptional<Bool>()
1349− // Optional ⬇
1350− let attachments = List<RealmMedia>()
1351− @objc dynamic var geo: Geolocation?
1352− // TODO: let postSource
1353− @objc dynamic var signed: User?
1354− @objc dynamic var ownerOfCopy: User?
1355− @objc dynamic var original: WallPost?
1356− let historyOfCopy = List<WallPost>()
1357− let canPin = RealmOptional<Bool>()
1358− let canEdit = RealmOptional<Bool>()
1359− let isPinned = RealmOptional<Bool>()
1360−
1361− // convenience init(id: WallPostID, ownerID: UserID, creatorID: UserID, date: Date, body: String, commentCount: Int, canPostComment: Bool, likeCount: Int, liked: Bool, canLike: Bool, repostCount: Int, didRepost: Bool, attachments: [Media], geo: Geolocation?, signed: UserID?, copyID: WallPostID?, canDelete: Bool, canPin: Bool?, canEdit: Bool?, isPinned: Bool?, copyHistory: [WallPostID], copyOwnerID: UserID?) {
1362− // self.id = id
1363− // self.ownerID = ownerID
1364− // self.creatorID = creatorID
1365− // self.date = date
1366− // self.body = body
1367− // self.commentCount = commentCount
1368− // self.canPostComment = canPostComment
1369− // self.likeCount = likeCount
1370− // self.liked = liked
1371− // self.canLike = canLike
1372− // self.repostCount = repostCount
1373− // self.didRepost = didRepost
1374− // self.attachments = attachments
1375− // self.geo = geo
1376− // self.signed = signed
1377− // self.copyID = copyID
1378− // self.canDelete = canDelete
1379− // self.canPin = canPin
1380− // self.canEdit = canEdit
1381− // self.isPinned = isPinned
1382− // self.copyHistory = copyHistory
1383− // self.copyOwnerID = copyOwnerID
1384− // }
1385−
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−// }
1406− 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− }
1412− }
1413− }
1414−
1415−
1416−
1417− override class func primaryKey() -> String? {
1418− return "id"
1419− }
1420−
1421− class func by(id: WallPostID) -> WallPost {
1422− let realm = try! Realm()
1423− if let us = realm.object(ofType: WallPost.self, forPrimaryKey: id) {
1424− return us
1425− } else {
1426− let us = WallPost()
1427− us.id = id
1428− realm.add(us)
1429− return us
1430− }
1431− }
1432−
1433−}
1434−typealias WallPostID = Int
1435−
1436−class WallPostReply: Object {
1437− @objc dynamic var id: WallPostReplyID = 0
1438− @objc dynamic var author: User?
1439− @objc dynamic var wallPost: WallPost?
1440− @objc dynamic var wallOwner: User?
1441− @objc dynamic var date: Date?
1442− @objc dynamic var body: String?
1443− let likeCount = RealmOptional<Int>()
1444− let didLike = RealmOptional<Bool>()
1445− let canLike = RealmOptional<Bool>()
1446− @objc dynamic var inReplyToUser: User?
1447− let attachments = List<RealmMedia>()
1448− @objc dynamic var inReplyToComment: WallPostReply?
1449− class func by(id: WallPostReplyID) -> WallPostReply {
1450− let realm = try! Realm()
1451− if let us = realm.object(ofType: WallPostReply.self, forPrimaryKey: id) {
1452− return us
1453− } else {
1454− let us = WallPostReply()
1455− us.id = id
1456− realm.add(us)
1457− return us
1458− }
1459− }
1460−
1461− func get(completion: (() -> ())) {
1462− // TODO: Get wallPostReply
1463− }
1464−
1465− override class func primaryKey() -> String? {
1466− return "id"
1467− }
1468−}
1469−typealias WallPostReplyID = Int
1470−
1471−class Sticker: Object {
1472− @objc dynamic var id: StickerID = 0
1473− @objc dynamic var packID: StickerPackID = 0
1474− @objc dynamic var image: RealmPhoto?
1475− var imageID: String {
1476− return "sticker\(id)image"
1477− }
1478− let width = RealmOptional<Int>()
1479− let height = RealmOptional<Int>()
1480−
1481− convenience init(id: StickerID, packID: StickerPackID, width: Int, height: Int) {
1482− self.init()
1483− self.id = id
1484− self.packID = packID
1485− self.width.value = width
1486− self.height.value = height
1487− }
1488− class func by(id: StickerID) -> Sticker {
1489− let realm = try! Realm()
1490− if let us = realm.object(ofType: Sticker.self, forPrimaryKey: id) {
1491− return us
1492− } else {
1493− let us = Sticker()
1494− us.id = id
1495− realm.add(us)
1496− return us
1497− }
1498− }
1499−
1500− override class func primaryKey() -> String? {
1501− return "id"
1502− }
1503− override static func ignoredProperties() -> [String] {
1504− return ["imageID"]
1505− }
1506−}
1507−typealias StickerID = Int
1508−typealias StickerPackID = Int
1509−
1510−class Gift: Object {
1511− @objc dynamic var id: GiftID = 0
1512− @objc dynamic var image: RealmPhoto?
1513− var imageID: String {
1514− return "gift\(id)image"
1515− }
1516− convenience init(id: GiftID, surl: String) {
1517− self.init()
1518− self.id = id
1519− self.image = RealmPhoto.by(imageID, surl: surl)
1520− }
1521− class func by(id: GiftID) -> Gift {
1522− let realm = try! Realm()
1523− if let us = realm.object(ofType: Gift.self, forPrimaryKey: id) {
1524− return us
1525− } else {
1526− let us = Gift()
1527− us.id = id
1528− realm.add(us)
1529− return us
1530− }
1531− }
1532−
1533− override class func primaryKey() -> String? {
1534− return "id"
1535− }
1536− override static func ignoredProperties() -> [String] {
1537− return ["imageID"]
1538− }
1539−}
1540−typealias GiftID = Int
1541−
1542−class Link: Object {
1543− var url: URL? {
1544− get {
1545− return surl =>> {URL(string: $0)}
1546− }
1547− }
1548− @objc dynamic var surl: String = ""
1549− @objc dynamic var title: String?
1550− @objc dynamic var caption: String?
1551− @objc dynamic var linkDescription: String?
1552− @objc dynamic var photo: Photo?
1553− let isExternal = RealmOptional<Bool>()
1554− //var product: Market?
1555− var rating: Rating? {
1556− get {
1557− if let stars = ratingStars.value,
1558− let count = ratingReviewCount.value {
1559− return Rating(stars: stars, reviewCount: count)
1560− }
1561− return nil
1562− }
1563− set {
1564− ratingStars.value = newValue?.stars
1565− ratingReviewCount.value = newValue?.reviewCount
1566− }
1567− }
1568− private let ratingStars = RealmOptional<Int>()
1569− private let ratingReviewCount = RealmOptional<Int>()
1570− //let application: Application?
1571− var button: LinkButton? {
1572− get {
1573− if let title = buttonTitle,
1574− let url = buttonURL {
1575− return LinkButton(title: title, url: url)
1576− }
1577− return nil
1578− }
1579− set {
1580− buttonURL = newValue?.url
1581− buttonTitle = newValue?.title
1582− }
1583− }
1584− @objc private dynamic var buttonTitle: String?
1585− private var buttonURL: URL? {
1586− get {
1587− return buttonSURL =>> {URL(string: $0)}
1588− }
1589− set {
1590− buttonSURL = newValue?.absoluteString
1591− }
1592− }
1593− private var buttonSURL: String?
1594− //let previewURL: URL
1595−
1596− class func by(surl: String) -> Link {
1597− let realm = try! Realm()
1598− if let us = realm.object(ofType: Link.self, forPrimaryKey: surl) {
1599− return us
1600− } else {
1601− let us = Link()
1602− us.surl = surl
1603− realm.add(us)
1604− return us
1605− }
1606− }
1607− override class func primaryKey() -> String? {
1608− return "surl"
1609− }
1610− override static func ignoredProperties() -> [String] {
1611− return ["url", "rating", "button", "buttonURL"]
1612− }
1613−}
1614−
1615−
1616−struct Rating {
1617− let stars: Int
1618− let reviewCount: Int
1619−}
1620−
1621−struct LinkButton {
1622− let title: String
1623− let url: URL
1624−}
1625−
1626−class Market: Object {
1627− @objc dynamic var id: MarketID = 0
1628− @objc dynamic var owner: User?
1629− @objc dynamic var title: String?
1630− @objc dynamic var marketDescription: String?
1631− let amount = RealmOptional<Int>()
1632− let price = RealmOptional<Int>()
1633− let currencyID = RealmOptional<CurrencyID>()
1634− @objc dynamic var currencyName: String?
1635− @objc dynamic var priceString: String?
1636− let categoryID = RealmOptional<MarketCategoryID>()
1637− @objc dynamic var categoryName: String?
1638− let sectionID = RealmOptional<MarketSectionID>()
1639− @objc dynamic var sectionName: String?
1640− @objc dynamic var image: RealmPhoto?
1641− var imageID: String {
1642− return "market\(id)image"
1643− }
1644− @objc dynamic var creationDate: Date?
1645− var availability: MarketAvailability? {
1646− set {
1647− availabilityInt.value = newValue?.rawValue
1648− }
1649− get {
1650− return availabilityInt.value =>> {MarketAvailability(rawValue: $0)}
1651− }
1652− }
1653− private let availabilityInt = RealmOptional<Int>()
1654− let photos = List<Photo>()
1655− let canComment = RealmOptional<Bool>()
1656− let canRepost = RealmOptional<Bool>()
1657− let likesCount = RealmOptional<Int>()
1658− let liked = RealmOptional<Bool>()
1659−
1660− class func by(id: MarketID) -> Market {
1661− let realm = try! Realm()
1662− if let us = realm.object(ofType: Market.self, forPrimaryKey: id) {
1663− return us
1664− } else {
1665− let us = Market()
1666− us.id = id
1667− realm.add(us)
1668− return us
1669− }
1670− }
1671−
1672− override class func primaryKey() -> String? {
1673− return "id"
1674− }
1675− override static func ignoredProperties() -> [String] {
1676− return ["imageID"]
1677− }
1678−}
1679−typealias CurrencyID = Int
1680−typealias MarketCategoryID = Int
1681−typealias MarketSectionID = Int
1682−enum MarketAvailability: Int {
1683− case availability = 0
1684− case deleted
1685− case notAvailability
1686−}
1687−typealias MarketID = Int
1688−
1689−class MarketAlbum: Object {
1690− @objc dynamic var id: MarketAlbumID = 0
1691− @objc dynamic var owner: User?
1692− @objc dynamic var title: String?
1693− @objc dynamic var photo: Photo?
1694− let count = RealmOptional<Int>()
1695− @objc dynamic var updateTime: Date?
1696− override class func primaryKey() -> String? {
1697− return "id"
1698− }
1699−}
1700−typealias MarketAlbumID = Int
1701−
1702−class Video: Object {
1703− @objc dynamic var id: VideoID = 0
1704− @objc dynamic var owner: User?
1705− @objc dynamic var title: String?
1706− @objc dynamic var videoDescription: String?
1707− let duration = RealmOptional<TimeInterval>()
1708− @objc dynamic var thumbnail: RealmPhoto?
1709− var thumbnailID: String {
1710− return "video\(id)thumbnail"
1711− }
1712− var player: URL? {
1713− get {
1714− return playerSURL =>> {URL(string: $0)}
1715− }
1716− set {
1717− playerSURL = newValue?.absoluteString
1718− }
1719− }
1720− @objc dynamic var playerSURL: String?
1721− @objc dynamic var accessKey: String?
1722− @objc dynamic var isProcessing: Bool = false
1723− @objc dynamic var isLive: Bool = false
1724− convenience init(id: VideoID, owner: User, title: String, description: String, duration: TimeInterval) {
1725− self.init()
1726− self.id = id
1727− self.owner = owner
1728− self.title = title
1729− self.videoDescription = description
1730− self.duration.value = duration
1731− }
1732−
1733− class func by(id: VideoID) -> Video {
1734− let realm = try! Realm()
1735− if let us = realm.object(ofType: Video.self, forPrimaryKey: id) {
1736− return us
1737− } else {
1738− let us = Video()
1739− us.id = id
1740− realm.add(us)
1741− return us
1742− }
1743− }
1744−
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−// }
1765− 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)
1770− }
1771− }
1772− }
1773−
1774− override class func primaryKey() -> String? {
1775− return "id"
1776− }
1777− override static func ignoredProperties() -> [String] {
1778− return ["player", "thumbnailID"]
1779− }
1780−}
1781−typealias VideoID = Int
1782−
1783−class Audio: Object {
1784− @objc dynamic var id: AudioID = 0
1785− @objc dynamic var owner: User?
1786− @objc dynamic var artist: String?
1787− @objc dynamic var title: String?
1788− let duration = RealmOptional<TimeInterval>()
1789− var url: URL? {
1790− get {
1791− return surl =>> {URL(string: $0)}
1792− }
1793− set {
1794− surl = newValue?.absoluteString
1795− }
1796− }
1797− @objc dynamic var surl: String?
1798−
1799− convenience init(id: AudioID) {
1800− self.init()
1801− self.id = id
1802− }
1803− class func by(id: AudioID) -> Audio {
1804− let realm = try! Realm()
1805− if let us = realm.object(ofType: Audio.self, forPrimaryKey: id) {
1806− return us
1807− } else {
1808− let us = Audio()
1809− us.id = id
1810− realm.add(us)
1811− return us
1812− }
1813− }
1814−
1815− override class func primaryKey() -> String? {
1816− return "id"
1817− }
1818− override static func ignoredProperties() -> [String] {
1819− return ["url"]
1820− }
1821−}
1822−typealias AudioID = Int
1823−typealias LyricID = Int
1824−typealias AudioAlbumID = Int
1825−typealias GenreID = Int
1826−
1827−class Document: Object {
1828− @objc dynamic var id: DocumentID = 0
1829− @objc dynamic var owner: User?
1830− @objc dynamic var title: String?
1831− let size = RealmOptional<Int>()
1832− @objc dynamic var fileExtension: String?
1833− var url: URL? {
1834− get {
1835− return surl =>> {URL(string: $0)}
1836− }
1837− set {
1838− surl = newValue?.absoluteString
1839− }
1840− }
1841− @objc dynamic var surl: String?
1842− @objc dynamic var image: RealmPhoto?
1843− var imageID: String {
1844− return "doc\(id)image"
1845− }
1846− var type: DocumentType? {
1847− get {
1848− return typeInt.value =>> {DocumentType(rawValue: $0)}
1849− }
1850− set {
1851− typeInt.value = newValue?.rawValue
1852− }
1853− }
1854− private let typeInt = RealmOptional<Int>()
1855− convenience init(id: DocumentID, owner: User, title: String, size: Int, ext: String, url: URL, type: DocumentType) {
1856− self.init()
1857− self.id = id
1858− self.owner = owner
1859− self.title = title
1860− self.size.value = size
1861− self.fileExtension = ext
1862− self.url = url
1863− self.type = type
1864− }
1865− class func by(id: DocumentID) -> Document {
1866− let realm = try! Realm()
1867− if let us = realm.object(ofType: Document.self, forPrimaryKey: id) {
1868− return us
1869− } else {
1870− let us = Document()
1871− us.id = id
1872− realm.add(us)
1873− return us
1874− }
1875− }
1876−
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−// }
1897− 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− }
1903− }
1904− }
1905−
1906− override class func primaryKey() -> String? {
1907− return "id"
1908− }
1909− override static func ignoredProperties() -> [String] {
1910− return ["url", "imageID"]
1911− }
1912−}
1913−typealias DocumentID = Int
1914−enum DocumentType: Int {
1915− case text = 1
1916− case archive
1917− case gif
1918− case image
1919− case audio
1920− case video
1921− case eBook
1922− case unknown
1923−}
1924−
1925−protocol Dialog {
1926− var firstMessage: Message? { get }
1927− var important: Bool { get set }
1928− var name: String? { get }
1929− func loadImage(into view: UIImageView, completion: (() -> ())?) -> RealmPhotoToken?
1930− var messages: Messages? { get }
1931− var id: Int { get }
1932− var lastReadMessageID: Int { get set }
1933− var count: RealmOptional<Int> { get }
1934− var notificationSettings: RealmNotificatonSettings? { get set }
1935− var peerID: Int { get }
1936−}
1937−
1938−func dialog(for id: DialogID) -> Dialog {
1939− if id > multichatchatId { // multichat
1940− let chat = Multichat.by(id: id - multichatchatId)
1941− return chat
1942−
1943− //} else if id < 0 { // Pablic
1944−
1945− } else { // Normal user
1946− let chat = Chat.by(user: User.by(id: id))
1947− return chat
1948− }
1949−}
1950−
1951−// For name conflicts
1952−func dialogFor(_ id: DialogID) -> Dialog {
1953− return dialog(for: id)
1954−}
1955−
1956−class RealmDialog: Object, Comparable {
1957−
1958− // TODO: Remove these two
1959− @objc dynamic var dateLastSent: Date?
1960− /// Number of times a message has been sent in the dateLastSent second
1961− @objc dynamic var dateSentNumber = 0
1962−
1963− var value: Dialog? {
1964− get {
1965− return dialog(for: id)
1966− }
1967− }
1968−
1969− var peerID: Int? {
1970− return value?.peerID
1971− }
1972−
1973− @objc dynamic var id: DialogID = 0
1974−
1975− @objc dynamic var date: Date?
1976−
1977− class func by(dialog: Dialog) -> RealmDialog {
1978− return RealmDialog.by(peerID: dialog.peerID)
1979− }
1980−
1981− class func by(peerID: Int) -> RealmDialog {
1982− if let dialog = (try? Realm())?.object(ofType: RealmDialog.self, forPrimaryKey: peerID) {
1983− return dialog
1984− } else {
1985− let dialog = RealmDialog()
1986− dialog.id = peerID
1987− realmWrite({ (realm) in
1988− realm.add(dialog)
1989− })
1990− return dialog
1991− }
1992− }
1993−
1994− override class func primaryKey() -> String? {
1995− return "id"
1996− }
1997− override static func ignoredProperties() -> [String] {
1998− return ["value", "peerID"]
1999− }
2000−}
2001−func ==(lhs: RealmDialog, rhs: RealmDialog) -> Bool {
2002− return lhs.date == rhs.date
2003−}
2004−func <(lhs: RealmDialog, rhs: RealmDialog) -> Bool {
2005− if let l = lhs.date,
2006− let r = rhs.date {
2007− return l < r
2008− } else {
2009− return false
2010− }
2011−}
2012−typealias DialogID = Int
2013−
2014−//func ==(lhs: Dialog, rhs: Dialog) -> Bool {
2015−// return lhs.date == rhs.date
2016−//}
2017−//func <(lhs: Dialog, rhs: Dialog) -> Bool {
2018−// return lhs.date < rhs.date
2019−//}
2020−
2021−class RealmNotificatonSettings: Object {
2022− var value: ChatNotificationSettings? {
2023− get {
2024− if let sound = notiSound.value,
2025− let never = notiDateNever.value {
2026− if never {
2027− return ChatNotificationSettings(sound: sound, disabledUntil: .never)
2028− } else {
2029− return notiDate >>> {ChatNotificationSettings(sound: sound, disabledUntil: .date($0))}
2030− }
2031− }
2032− return nil
2033− }
2034− set {
2035− notiSound.value = newValue?.sound
2036− if let newV = newValue {
2037− switch newV.disabledUntil {
2038− case .date(let date):
2039− notiDate = date
2040− notiDateNever.value = false
2041− case .never:
2042− notiDateNever.value = true
2043− notiDate = nil
2044− }
2045− }
2046− }
2047− }
2048− private let notiSound = RealmOptional<Bool>()
2049− private let notiDateNever = RealmOptional<Bool>()
2050− @objc private dynamic var notiDate: Date?
2051− convenience init(value: ChatNotificationSettings?) {
2052− self.init()
2053− self.value = value
2054− }
2055−}
2056−
2057−class Multichat: Object {
2058− @objc dynamic var id: MultichatID = 0
2059− @objc dynamic var admin: User?
2060− var timers: [UserID: Timer] = [:]
2061− var typingUsers: Set<User> = []
2062− @objc dynamic var title: String?
2063− let users = List<MultiChatUser>()
2064− @objc dynamic var messages: Messages?
2065− // let messages = List<Message>()
2066− @objc dynamic var lastReadMessageID = 0
2067− @objc dynamic var important = false
2068− @objc dynamic var answered = false
2069− @objc dynamic var date = Date()
2070− let count = RealmOptional<Int>()
2071− @objc dynamic var image: RealmPhoto?
2072− var imageID: String {
2073− return "mchat\(id)image"
2074− }
2075− let attachments = List<RealmMedia>()
2076−
2077− @objc dynamic var notificationSettings: RealmNotificatonSettings?
2078−
2079− var participationStatus: MultichatStatus? {
2080− get {
2081− return participationStatusInt.value =>> {MultichatStatus(rawValue: $0)}
2082− }
2083− set {
2084− participationStatusInt.value = newValue?.rawValue
2085− }
2086− }
2087− private let participationStatusInt = RealmOptional<Int>()
2088−
2089− // convenience init(id: MultichatID, adminID: UserID, title: String, userIDs: [(user: UserID, invitedBy: UserID)]?, notificationSettings: MultichatNotificationSettings?, participationStatus: MultichatStatus?) {
2090− // self.id = id
2091− // self.adminID = adminID
2092− // self.title = title
2093− // self.userIDs = userIDs
2094− // self.notificationSetting = notificationSettings
2095− // self.participationStatus = participationStatus
2096− // }
2097− class func by(id: MultichatID) -> Multichat {
2098− let realm = try! Realm()
2099− if let us = realm.object(ofType: Multichat.self, forPrimaryKey: id) {
2100− return us
2101− } else {
2102−// VkServices.getMultichat(for: id)
2103− let us = Multichat()
2104− realmWrite { realm in
2105− us.id = id
2106− us.messages = Messages.by(id: us.peerID)
2107− realm.add(us)
2108− }
2109− return us
2110− }
2111− }
2112−
2113− override class func primaryKey() -> String? {
2114− return "id"
2115− }
2116− override static func ignoredProperties() -> [String] {
2117− return ["imageID", "typingUsers", "timers"]
2118− }
2119−}
2120−
2121−extension Multichat: Dialog {
2122− var firstMessage: Message? {
2123− return messages?.first
2124− }
2125−
2126− var name: String? {
2127− return title
2128− }
2129−
2130− func loadImage(into view: UIImageView, completion: (() -> ())? = nil) -> RealmPhotoToken? {
2131− return image?.load(into: view, completion: completion)
2132− }
2133− // func image(completion: @escaping ((UIImage?) -> ())) {
2134− // if let im = image?.image {
2135− // im(completion)
2136− // } else {
2137− // completion(nil)
2138− // }
2139− // }
2140−
2141− var peerID: Int {
2142− return id + multichatchatId
2143− }
2144−}
2145−
2146−class MultiChatUser: Object {
2147− @objc dynamic var user: User?
2148− @objc dynamic var invitedBy: User?
2149− convenience init(_ user: User, invitedBy: User) {
2150− self.init()
2151− self.user = user
2152− self.invitedBy = invitedBy
2153− }
2154−}
2155−
2156−enum MultichatStatus: Int {
2157− case active
2158− case left
2159− case kicked
2160−}
2161−
2162−class Chat: Object {
2163− @objc dynamic var user: User? {
2164− didSet {
2165− user >>> {userID = $0.id}
2166− }
2167− }
2168− var timer: Timer?
2169− @objc dynamic var date = Date()
2170− @objc dynamic var userID = 0
2171− @objc dynamic var isTyping = false
2172− @objc dynamic var lastReadMessageID = 0
2173− let count = RealmOptional<Int>()
2174− @objc dynamic var messages: Messages?
2175− // let messages = List<Message>()
2176− @objc dynamic var important = false
2177− @objc dynamic var answered = false
2178− let attachments = List<RealmMedia>()
2179− @objc dynamic var notificationSettings: RealmNotificatonSettings?
2180− class func by(user: User) -> Chat {
2181− let realm = try! Realm()
2182− if let us = realm.object(ofType: Chat.self, forPrimaryKey: user.id) {
2183− return us
2184− } else {
2185− let us = Chat()
2186− realmWrite { realm in
2187− us.user = user
2188− us.messages = Messages.by(id: us.peerID)
2189− realm.add(us)
2190− }
2191− return us
2192− }
2193− }
2194−
2195− convenience init(user: User) {
2196− self.init()
2197− self.user = user
2198− }
2199− override static func ignoredProperties() -> [String] {
2200− return ["timer"]
2201− }
2202− override class func primaryKey() -> String? {
2203− return "userID"
2204− }
2205−}
2206−
2207−extension Chat: Dialog {
2208− var firstMessage: Message? {
2209− return messages?.first
2210− }
2211−
2212− var name: String? {
2213− if let firstName = user?.firstName,
2214− let lastName = user?.lastName {
2215− return "\(firstName) \(lastName)"
2216− } else {
2217− return nil
2218− }
2219− }
2220−
2221− func loadImage(into view: UIImageView, completion: (() -> ())? = nil) -> RealmPhotoToken? {
2222− return user?.avatar?.load(into: view, completion: completion)
2223− }
2224−
2225− // func image(completion: @escaping ((UIImage?) -> ())) {
2226− // if let im = user?.avatar?.image {
2227− // im(completion)
2228− // } else {
2229− // completion(nil)
2230− // }
2231− // }
2232−
2233− var id: Int {
2234− return userID
2235− }
2236−
2237− var peerID: Int {
2238− return userID
2239− }
2240−}
2241−
2242−struct ChatNotificationSettings {
2243− var sound: Bool
2244− var disabledUntil: disableDate
2245−}
2246−
2247−enum disableDate {
2248− case never
2249− case date(Date)
2250− init?(value: Int) {
2251− switch value {
2252− case -1:
2253− self = .never
2254− case 0:
2255− return nil
2256− default:
2257− self = .date(Date(timeIntervalSince1970: TimeInterval(value)))
2258− }
2259− }
2260−}
2261−
2262−func isPhoneNumber(_ phone: String) -> Bool {
2263− let nums = "1234567890".characters
2264− let f002 = phone.characters.map{nums.contains($0) ? 1 : 0}
2265− let foo1 = Double(sum(acc: 0, arr: f002))
2266− let foo = foo1/Double(phone.characters.count)
2267− return foo >= 0.4 ? true : false
2268−}
2269−
2270−