@@ -0,0 +1,2270 @@
5+// Created by Ilya Kos on 12/12/16.
6+// Copyright © 2016 Ilya Kos. All rights reserved.
18+typealias Token = String
19+typealias UserID = Int
20+typealias MessageID = Int
21+typealias MultichatID = Int
23+class RealmPhoto: Object {
25+ convenience init(surl: String, id: String) {
27+ self.imageSURL = surl
31+ @objc dynamic var id: String = ""
34+ return imageSURL =>> {URL(string: $0)}
37+ imageSURL = newValue?.absoluteString
40+ @objc dynamic var imageSURL: String? {
42+ if oldValue != imageSURL {
47+ @objc private dynamic var localImageSURL: String? {
49+ if oldValue != localImageSURL {
54+ private var imageCache: UIImage?
56+ convenience init(id: String, surl: String?) {
59+ self.imageSURL = surl
62+ class func by(_ id: String, surl: String?) -> RealmPhoto {
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}
70+ surl =>> {ob.imageSURL = $0}
75+ let ob = RealmPhoto(id: id, surl: surl)
76+ if realm.isInWriteTransaction {
86+ let ob = RealmPhoto(id: id, surl: surl)
91+ override static func primaryKey() -> String? {
95+ override static func ignoredProperties() -> [String] {
96+ return ["imageURL", "imageCache", "completions", "request"]
99+ var completions: [((() -> ()), RealmPhotoToken)] = []
100+ var views: [(UIImageView?, RealmPhotoToken)] = []
101+ var request: DataRequest?
103+ @discardableResult func load(into view: UIImageView, completion: (() -> ())? = nil, error errorClosure: (() -> ())? = nil) -> RealmPhotoToken {
105+ let token = RealmPhotoToken()
107+ func getFromServer() {
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
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
122+ self.imageCache = image
123+ DispatchQueue.main.async {
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 = []
131+ case .failure(let error):
133+ // TODO: Error handling
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
145+ case .fulfilled(let image):
150+ case .rejected(let error): // TODO: Handle error?
151+ completion >>> {self.completions.append(($0, token))}
152+ self.views.append((view, token))
157+ completion >>> {self.completions.append(($0, token))}
158+ self.views.append((view, token))
165+ // func image(_ completion: @escaping ((UIImage?) -> ())) {
167+ // let surl = "\(id).png"
168+ // if imageCache != nil {
169+ // print("we have caching!")
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 {
183+ // let realm = try Realm()
184+ // if !realm.isInWriteTransaction {
185+ // try realm.write {
186+ // self.localImageSURL = surl
189+ // self.localImageSURL = surl
194+ // self.imageCache = image
195+ // DispatchQueue.main.async {completion(image)}
197+ // case .failure(let error):
198+ // // TODO: Error handling
206+public class RealmPhotoToken {
207+ public func cancel() {
210+ fileprivate var isValid = true
215+ @objc dynamic var id: UserID = 0
216+ @objc dynamic var firstName: String?
217+ @objc dynamic var lastName: String?
218+ var deactivated: Deactivated? {
220+ return deactivatedStr =>> {Deactivated.init(rawValue: $0)}
223+ deactivatedStr = newValue >>> {$0.rawValue}
226+ @objc private dynamic var deactivatedStr: String?
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? {
240+ return friendStatusInt.value =>> {FriendStatus(rawValue: $0)}
243+ friendStatusInt.value = newValue >>> {$0.rawValue}
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"
252+ @objc dynamic var photo: RealmPhoto?
253+ var photoID: String {
254+ return "user\(id)photo"
258+ return siteSURL =>> {URL.init(string: $0)}
261+ siteSURL = newValue >>> {$0.absoluteString}
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>()
270+ convenience init(id: UserID, firstName: String, lastName: String) {
273+ self.firstName = firstName
274+ self.lastName = lastName
275+ // self.lastUpdated = Date()
277+ class func by(id: UserID) -> User {
278+ let realm = try! Realm()
279+ if let us = realm.object(ofType: User.self, forPrimaryKey: id) {
284+ if realm.isInWriteTransaction {
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)
304+// }, onError: { (error) in
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)
318+ override static func primaryKey() -> String? {
322+ override static func ignoredProperties() -> [String] {
323+ return ["site", "photoID", "avatarID"]
325+ // func update() { lastUpdated = Date() }
327+ // MARK: Hashable override
329+ override var hashValue: Int {
334+class Geolocation: Object {
335+ var geoCoordinates: CLLocation? {
337+ if let long = long.value, let latt = latt.value {
338+ return CLLocation(latitude: latt, longitude: long)
343+ if let latt = newValue?.coordinate.latitude,
344+ let long = newValue?.coordinate.longitude {
345+ self.latt.value = latt
346+ self.long.value = long
348+ self.long.value = nil
349+ self.latt.value = nil
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"
362+ var country: String?
364+ override static func ignoredProperties() -> [String] {
365+ return ["geoCoordinates", "imageID"]
367+ convenience init(long: Double, latt: Double) {
369+ self.long.value = long
370+ self.latt.value = latt
375+class GenericMessage: Object {
376+ @objc dynamic var date = Date() //
377+ @objc dynamic var body = "" //
378+ @objc dynamic var user: User?
380+ var outPhotos: [UIImage] = [] // TODO: ~
382+ @objc dynamic var geolocation: Geolocation?
384+ let attachments = List<RealmMedia>()
385+ let forwardedMessages = List<RealmForwardedMessage>()
386+ //let sentMessageId: MessageID? I DONT KNOW WHY I PUT THIS HERE
388+ // convenience init(body: String) {
391+ // self.out.value = true
393+ // convenience init(image: UIImage) {
395+ // self.outPhotos.append(image)
397+ override static func ignoredProperties() -> [String] {
398+ return ["outPhotos"]
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
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 {
418+ return self.id == message.id
420+ internal func greater(than message: Message) -> Bool {
421+ return self.id < message.id
424+ static func ==(lhs: Message, rhs: Message) -> Bool {
425+ print("\(lhs.id) \(rhs.id) \(lhs.id == rhs.id)")
426+ return lhs.id == rhs.id
429+ @objc dynamic var out = false
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>()
439+ var action: ServiceMessageAction? {
441+ func getUser() -> ServiceMessageUser? {
442+ if let user = self.serviceMessageUser {
444+ } else if let email = self.serviceMessageString {
445+ return .email(email)
451+ return serviceMessage.value =>> { service in
458+ return self.serviceMessageString >>> { .create($0) }
460+ return self.serviceMessageString >>> { .titleUpdate($0) }
462+ return getUser() >>> { .inviteUser($0) }
464+ return getUser() >>> { .kickUser($0) }
471+ func set(user: ServiceMessageUser) {
473+ case .user(let use):
474+ self.serviceMessageUser = use
475+ case .email(let str):
476+ self.serviceMessageString = str
480+ serviceMessageString = nil
481+ serviceMessageUser = nil
482+ serviceMessage.value = newValue >>> { new in
488+ case .create(let str):
489+ self.serviceMessageString = str
491+ case .titleUpdate(let str):
492+ self.serviceMessageString = str
494+ case .inviteUser(let user):
497+ case .kickUser(let user):
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)
513+// }, onError: { (error) in
516+// // TODO: Implement propperly?
519+ class func by(id: MessageID) -> Message {
520+ let realm = try! Realm()
521+ if let us = realm.object(ofType: Message.self, forPrimaryKey: id) {
533+ override static func primaryKey() -> String? {
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
541+func <(lhs: Message, rhs: Message) -> Bool {
542+ return lhs.id < rhs.id
545+enum forwardedMessage {
546+ case genericMessage(GenericMessage)
547+ case message(Message)
550+class RealmForwardedMessage: Object {
551+ var value: forwardedMessage? {
553+ if let gm = genericMessage {
554+ return .genericMessage(gm)
555+ } else if let m = message {
563+ if let fm = newValue {
565+ case .genericMessage(let gm):
568+ case .message(let m):
569+ genericMessage = nil
574+ genericMessage = nil
579+ @objc private dynamic var genericMessage: GenericMessage?
580+ @objc private dynamic var message: Message?
582+ var id: MessageID? {
583+ if let m = message {
590+ convenience init(value: forwardedMessage) {
595+ override static func ignoredProperties() -> [String] {
600+//struct Geolocation {
601+// var coordinates: CLLocation
602+// var title: String?
603+// var imageURL: URL? {
605+// return imageSURL =>> {URL.init(string: $0)}
608+// imageSURL = newValue?.absoluteString
611+// var imageSURL: String?
612+// // func image(completion: ((UIImage) -> ())) {
613+// // imageFunc =>> {$0(completion)}
615+// var image: (@escaping ((UIImage) -> ()) -> ())?
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
624+// self.country = country
627+typealias GeolocationID = Int
629+enum Deactivated: String {
630+ case banned = "banned"
631+ case deleted = "deleted"
632+ case normal = "normal"
635+enum FriendStatus: Int {
638+ case requestRecieved
642+enum MessageReadState: Int {
646+enum MessageSendState: Int {
651+enum MultichatNotificationSetting {
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
665+enum ServiceMessageUser {
670+typealias MessageChunkID = String
671+class MessageChunk: Object { // message ids go down
672+ subscript(index: Int) -> Message {
673+ return messages[index]
676+ @objc dynamic var id: MessageChunkID = ""
678+ fileprivate let messages = List<Message>()
680+ var firstMessage: Message? {
681+ return messages.first
684+ var lastMessage: Message? {
685+ return messages.last
688+ var firstID: MessageID? {
689+ return firstMessage?.id
692+ var lastID: MessageID? {
693+ return lastMessage?.id
697+ return messages.count
700+ fileprivate func append(message: Message?) {
701+ message >>> {messages.append($0)}
704+ override static func primaryKey() -> String? {
708+ override static func ignoredProperties() -> [String] {
709+ return ["firstMessage", "lastMessage", "firstID", "lastID", "count"]
713+func +=(lhs: MessageChunk, rhs: MessageChunk) {
714+ lhs.messages.append(objectsIn: rhs.messages)
717+/// Returns: true if added. false if was already in list
718+func <~(lhs: MessageChunk?, rhs: Message?) -> Bool {
719+ var out: Bool = false
721+ out = lhs?.messages <~ rhs
725+/// Returns: Indexes of added items
726+func <-(lhs: MessageChunk?, rhs: [Message?]?) -> [Int] {
729+ out = lhs?.messages <- rhs
733+/// Returns: Indexes of added items
734+func <-(lhs: MessageChunk?, rhs: MessageChunk?) -> [Int] {
737+ out = lhs?.messages <- rhs?.messages
743+ case message(Message)
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 {
756+ while messageChunks[i].count < index {
757+ index -= messageChunks[i].count + 1
760+ if index == messageChunks[i].count {
763+ return .message(messageChunks[i][index])
767+ @objc dynamic var id: MessagesID = 0
769+ @objc fileprivate dynamic var lastChunkID = 0
772+ return messageChunks.endIndex
775+ var first: Message? {
776+ return messageChunks.first?.firstMessage
779+ func count(upToChunk index: Int) -> Int {
781+ for i in 0..<index {
782+ n += messageChunks[i].count + 1
787+ public var count: Int {
788+ var n = messageChunks.count - 1
789+ for chunk in messageChunks {
795+ fileprivate let messageChunks = List<MessageChunk>()
797+ public var chunks: List<MessageChunk> {
798+ return messageChunks
801+ fileprivate enum ChunkIndex {
807+ fileprivate func createChunk(at index: Int = 0) -> MessageChunk {
808+ let chunk = MessageChunk()
809+ realmWrite { (realm) in
810+ chunk.id = "\(id)_\(lastChunkID)"
813+ messageChunks.insert(chunk, at: index)
818+ /// Return nil if there are no chunks
819+ fileprivate func chunkIndex(of message: Message) -> ChunkIndex? {
820+ if messageChunks.count == 0 {
823+ if let first = messageChunks.first?.firstMessage {
824+ if first.greater(than: message) {
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) { // [ ... | ()] [...] ...
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) {
845+ return .after(endIndex-1)
849+ override static func primaryKey() -> String? {
853+ override static func ignoredProperties() -> [String] {
857+ class func by(id: MessagesID) -> Messages {
858+ let realm = try! Realm()
859+ if let us = realm.object(ofType: Messages.self, forPrimaryKey: id) {
869+ // MARK: Messages obesrver
871+ static let notificationName: Notification.Name = Notification.Name(rawValue: "MessagesWereModifiedNotificationName")
882+/// Returns: true if added. false if was already in list
883+func <~(lhs: Messages?, rhs: Message?) -> Bool {
884+ var out: Bool = false
888+ if let index = lhs.chunkIndex(of: rhs) {
891+ lhs.messageChunks[i].append(message: rhs)
893+ case .inside(let i):
894+ out = lhs.messageChunks[i] <~ rhs
896+ out = lhs.createChunk(at: 0) <~ rhs
899+ out = lhs.createChunk() <~ rhs
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]*/ {
911+ let rhs = rhs?.flatMap({$0}),
912+ let first = rhs.first,
913+ let last = rhs.last {
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) {
922+ print("\t", startI, endI)
924+ case .inside(let i):
934+ case .inside(let i):
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)
947+ for i in 0..<spacerIndexes.count {
948+ spacerIndexes[i] -= dIndex
949+ deleted.append(spacerIndexes[i])
950+ spacerIndexes[i] -= count
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)
961+ let chunk = lhs.chunks[start]
962+ addedMs = chunk <- rhs
964+ addedMs.map {$0 + count}
968+ print("after notification", lhs.chunks)
969+ NotificationCenter.default.post(name: Messages.notificationName,
971+ userInfo: [Messages.Changes.added: added,
972+ Messages.Changes.modified: modified,
973+ Messages.Changes.deleted: deleted])
976+ } else { // within one
977+ assert(start == end, "start index is larger than end index!")
978+ realmWriteWithCompletion { _, completion in
980+ added += lhs.createChunk(at: 0) <- rhs
981+ added.append(0) // IDK o[]o[]o []o[]o
983+ added += (lhs.messageChunks[start] <- rhs).map {$0 + lhs.count(upToChunk: start)}
986+ NotificationCenter.default.post(name: Messages.notificationName,
988+ userInfo: [Messages.Changes.added: added,
989+ Messages.Changes.modified: modified,
990+ Messages.Changes.deleted: deleted])
995+ realmWriteWithCompletion { _, completion in
996+ added += lhs.createChunk() <- rhs
998+ NotificationCenter.default.post(name: Messages.notificationName,
1000+ userInfo: [Messages.Changes.added: added,
1001+ Messages.Changes.modified: modified,
1002+ Messages.Changes.deleted: deleted])
1017+ case wall(WallPost)
1018+ case wallReply(WallPostReply)
1019+ case sticker(Sticker)
1022+ case market(Market)
1023+ case marketAlbum(MarketAlbum)
1024+ case graffiti(Document)
1027+ case album(PhotoAlbum)
1028+ var realm: RealmMedia {
1029+ return RealmMedia(value: self)
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?
1050+ var value: Media? {
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) }
1087+ if let val = newValue {
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
1108+ convenience init(value: Media) {
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) {
1127+ self.question = question
1128+ self.votes.value = votes
1129+ // self.answerID.value = answerID
1131+ class func by(id: PollID) -> Poll {
1132+ let realm = try! Realm()
1133+ if let us = realm.object(ofType: Poll.self, forPrimaryKey: id) {
1143+ override class func primaryKey() -> String? {
1147+typealias PollID = Int
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
1155+ convenience init(id: PollAnswerID, body: String, votes: Int, rating: Int) {
1160+ self.rating = rating
1163+typealias PollAnswerID = Int
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?
1173+ return surl =>> {URL(string: $0)}
1176+ surl = newValue >>> {$0.absoluteString}
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) {
1189+ self.commentCount.value = commentCount
1191+ class func by(id: NoteID) -> Note {
1192+ let realm = try! Realm()
1193+ if let us = realm.object(ofType: Note.self, forPrimaryKey: id) {
1202+ override class func ignoredProperties() -> [String] {
1206+ override class func primaryKey() -> String? {
1210+typealias NoteID = Int
1212+typealias GraffitiID = Int
1213+class Graffiti: Document {
1214+} // Use document.image ?
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"
1224+ @objc dynamic var image: RealmPhoto?
1225+ var imageID: String {
1226+ return "photo\(id)image"
1228+ let width = RealmOptional<Int>()
1229+ let height = RealmOptional<Int>()
1230+ @objc dynamic var accessKey: Key?
1232+ convenience init(id: PhotoID, owner: User, date: Date){
1239+ class func by(id: PhotoID) -> Photo {
1240+ let realm = try! Realm()
1241+ if let us = realm.object(ofType: Photo.self, forPrimaryKey: id) {
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)")
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)
1264+// }, onError: { (error) in
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)
1280+ override class func primaryKey() -> String? {
1284+ override static func ignoredProperties() -> [String] {
1285+ return ["thumbnailID", "imageID"]
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) {
1304+ override class func primaryKey() -> String? {
1307+ class func by(id: PhotoAlbumID) -> PhotoAlbum {
1308+ let realm = try! Realm()
1309+ if let us = realm.object(ofType: PhotoAlbum.self, forPrimaryKey: id) {
1312+ let us = PhotoAlbum()
1320+ // init(id: PhotoAlbumID, thumbID: PhotoID, ownerID: UserID, title: String, dateCreated: Date, dateUpdated: Date, count: Int) {
1322+ // self.thumbID = thumbID
1323+ // self.ownerID = ownerID
1324+ // self.title = title
1325+ // self.dateCreated = dateCreated
1326+ // self.dateUpdated = dateUpdated
1327+ // self.count = count
1331+typealias PhotoID = Int
1332+typealias PhotoAlbumID = Int
1333+typealias Key = String
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>()
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>()
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?) {
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
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
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)")
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)
1399+// }, onError: { (error) in
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)
1417+ override class func primaryKey() -> String? {
1421+ class func by(id: WallPostID) -> WallPost {
1422+ let realm = try! Realm()
1423+ if let us = realm.object(ofType: WallPost.self, forPrimaryKey: id) {
1426+ let us = WallPost()
1434+typealias WallPostID = Int
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) {
1454+ let us = WallPostReply()
1461+ func get(completion: (() -> ())) {
1462+ // TODO: Get wallPostReply
1465+ override class func primaryKey() -> String? {
1469+typealias WallPostReplyID = Int
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"
1478+ let width = RealmOptional<Int>()
1479+ let height = RealmOptional<Int>()
1481+ convenience init(id: StickerID, packID: StickerPackID, width: Int, height: Int) {
1484+ self.packID = packID
1485+ self.width.value = width
1486+ self.height.value = height
1488+ class func by(id: StickerID) -> Sticker {
1489+ let realm = try! Realm()
1490+ if let us = realm.object(ofType: Sticker.self, forPrimaryKey: id) {
1500+ override class func primaryKey() -> String? {
1503+ override static func ignoredProperties() -> [String] {
1507+typealias StickerID = Int
1508+typealias StickerPackID = Int
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"
1516+ convenience init(id: GiftID, surl: String) {
1519+ self.image = RealmPhoto.by(imageID, surl: surl)
1521+ class func by(id: GiftID) -> Gift {
1522+ let realm = try! Realm()
1523+ if let us = realm.object(ofType: Gift.self, forPrimaryKey: id) {
1533+ override class func primaryKey() -> String? {
1536+ override static func ignoredProperties() -> [String] {
1540+typealias GiftID = Int
1542+class Link: Object {
1545+ return surl =>> {URL(string: $0)}
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? {
1557+ if let stars = ratingStars.value,
1558+ let count = ratingReviewCount.value {
1559+ return Rating(stars: stars, reviewCount: count)
1564+ ratingStars.value = newValue?.stars
1565+ ratingReviewCount.value = newValue?.reviewCount
1568+ private let ratingStars = RealmOptional<Int>()
1569+ private let ratingReviewCount = RealmOptional<Int>()
1570+ //let application: Application?
1571+ var button: LinkButton? {
1573+ if let title = buttonTitle,
1574+ let url = buttonURL {
1575+ return LinkButton(title: title, url: url)
1580+ buttonURL = newValue?.url
1581+ buttonTitle = newValue?.title
1584+ @objc private dynamic var buttonTitle: String?
1585+ private var buttonURL: URL? {
1587+ return buttonSURL =>> {URL(string: $0)}
1590+ buttonSURL = newValue?.absoluteString
1593+ private var buttonSURL: String?
1594+ //let previewURL: URL
1596+ class func by(surl: String) -> Link {
1597+ let realm = try! Realm()
1598+ if let us = realm.object(ofType: Link.self, forPrimaryKey: surl) {
1607+ override class func primaryKey() -> String? {
1610+ override static func ignoredProperties() -> [String] {
1611+ return ["url", "rating", "button", "buttonURL"]
1618+ let reviewCount: Int
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"
1644+ @objc dynamic var creationDate: Date?
1645+ var availability: MarketAvailability? {
1647+ availabilityInt.value = newValue?.rawValue
1650+ return availabilityInt.value =>> {MarketAvailability(rawValue: $0)}
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>()
1660+ class func by(id: MarketID) -> Market {
1661+ let realm = try! Realm()
1662+ if let us = realm.object(ofType: Market.self, forPrimaryKey: id) {
1672+ override class func primaryKey() -> String? {
1675+ override static func ignoredProperties() -> [String] {
1679+typealias CurrencyID = Int
1680+typealias MarketCategoryID = Int
1681+typealias MarketSectionID = Int
1682+enum MarketAvailability: Int {
1683+ case availability = 0
1685+ case notAvailability
1687+typealias MarketID = Int
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? {
1700+typealias MarketAlbumID = Int
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"
1714+ return playerSURL =>> {URL(string: $0)}
1717+ playerSURL = newValue?.absoluteString
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) {
1729+ self.videoDescription = description
1730+ self.duration.value = duration
1733+ class func by(id: VideoID) -> Video {
1734+ let realm = try! Realm()
1735+ if let us = realm.object(ofType: Video.self, forPrimaryKey: id) {
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)")
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)
1758+// }, onError: { (error) in
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)
1774+ override class func primaryKey() -> String? {
1777+ override static func ignoredProperties() -> [String] {
1778+ return ["player", "thumbnailID"]
1781+typealias VideoID = Int
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>()
1791+ return surl =>> {URL(string: $0)}
1794+ surl = newValue?.absoluteString
1797+ @objc dynamic var surl: String?
1799+ convenience init(id: AudioID) {
1803+ class func by(id: AudioID) -> Audio {
1804+ let realm = try! Realm()
1805+ if let us = realm.object(ofType: Audio.self, forPrimaryKey: id) {
1815+ override class func primaryKey() -> String? {
1818+ override static func ignoredProperties() -> [String] {
1822+typealias AudioID = Int
1823+typealias LyricID = Int
1824+typealias AudioAlbumID = Int
1825+typealias GenreID = Int
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?
1835+ return surl =>> {URL(string: $0)}
1838+ surl = newValue?.absoluteString
1841+ @objc dynamic var surl: String?
1842+ @objc dynamic var image: RealmPhoto?
1843+ var imageID: String {
1844+ return "doc\(id)image"
1846+ var type: DocumentType? {
1848+ return typeInt.value =>> {DocumentType(rawValue: $0)}
1851+ typeInt.value = newValue?.rawValue
1854+ private let typeInt = RealmOptional<Int>()
1855+ convenience init(id: DocumentID, owner: User, title: String, size: Int, ext: String, url: URL, type: DocumentType) {
1860+ self.size.value = size
1861+ self.fileExtension = ext
1865+ class func by(id: DocumentID) -> Document {
1866+ let realm = try! Realm()
1867+ if let us = realm.object(ofType: Document.self, forPrimaryKey: id) {
1870+ let us = Document()
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)")
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)
1890+// }, onError: { (error) in
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)
1906+ override class func primaryKey() -> String? {
1909+ override static func ignoredProperties() -> [String] {
1910+ return ["url", "imageID"]
1913+typealias DocumentID = Int
1914+enum DocumentType: Int {
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 }
1938+func dialog(for id: DialogID) -> Dialog {
1939+ if id > multichatchatId { // multichat
1940+ let chat = Multichat.by(id: id - multichatchatId)
1943+ //} else if id < 0 { // Pablic
1945+ } else { // Normal user
1946+ let chat = Chat.by(user: User.by(id: id))
1951+// For name conflicts
1952+func dialogFor(_ id: DialogID) -> Dialog {
1953+ return dialog(for: id)
1956+class RealmDialog: Object, Comparable {
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
1963+ var value: Dialog? {
1965+ return dialog(for: id)
1970+ return value?.peerID
1973+ @objc dynamic var id: DialogID = 0
1975+ @objc dynamic var date: Date?
1977+ class func by(dialog: Dialog) -> RealmDialog {
1978+ return RealmDialog.by(peerID: dialog.peerID)
1981+ class func by(peerID: Int) -> RealmDialog {
1982+ if let dialog = (try? Realm())?.object(ofType: RealmDialog.self, forPrimaryKey: peerID) {
1985+ let dialog = RealmDialog()
1987+ realmWrite({ (realm) in
1994+ override class func primaryKey() -> String? {
1997+ override static func ignoredProperties() -> [String] {
1998+ return ["value", "peerID"]
2001+func ==(lhs: RealmDialog, rhs: RealmDialog) -> Bool {
2002+ return lhs.date == rhs.date
2004+func <(lhs: RealmDialog, rhs: RealmDialog) -> Bool {
2005+ if let l = lhs.date,
2012+typealias DialogID = Int
2014+//func ==(lhs: Dialog, rhs: Dialog) -> Bool {
2015+// return lhs.date == rhs.date
2017+//func <(lhs: Dialog, rhs: Dialog) -> Bool {
2018+// return lhs.date < rhs.date
2021+class RealmNotificatonSettings: Object {
2022+ var value: ChatNotificationSettings? {
2024+ if let sound = notiSound.value,
2025+ let never = notiDateNever.value {
2027+ return ChatNotificationSettings(sound: sound, disabledUntil: .never)
2029+ return notiDate >>> {ChatNotificationSettings(sound: sound, disabledUntil: .date($0))}
2035+ notiSound.value = newValue?.sound
2036+ if let newV = newValue {
2037+ switch newV.disabledUntil {
2038+ case .date(let date):
2040+ notiDateNever.value = false
2042+ notiDateNever.value = true
2048+ private let notiSound = RealmOptional<Bool>()
2049+ private let notiDateNever = RealmOptional<Bool>()
2050+ @objc private dynamic var notiDate: Date?
2051+ convenience init(value: ChatNotificationSettings?) {
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"
2075+ let attachments = List<RealmMedia>()
2077+ @objc dynamic var notificationSettings: RealmNotificatonSettings?
2079+ var participationStatus: MultichatStatus? {
2081+ return participationStatusInt.value =>> {MultichatStatus(rawValue: $0)}
2084+ participationStatusInt.value = newValue?.rawValue
2087+ private let participationStatusInt = RealmOptional<Int>()
2089+ // convenience init(id: MultichatID, adminID: UserID, title: String, userIDs: [(user: UserID, invitedBy: UserID)]?, notificationSettings: MultichatNotificationSettings?, participationStatus: MultichatStatus?) {
2091+ // self.adminID = adminID
2092+ // self.title = title
2093+ // self.userIDs = userIDs
2094+ // self.notificationSetting = notificationSettings
2095+ // self.participationStatus = participationStatus
2097+ class func by(id: MultichatID) -> Multichat {
2098+ let realm = try! Realm()
2099+ if let us = realm.object(ofType: Multichat.self, forPrimaryKey: id) {
2102+// VkServices.getMultichat(for: id)
2103+ let us = Multichat()
2104+ realmWrite { realm in
2106+ us.messages = Messages.by(id: us.peerID)
2113+ override class func primaryKey() -> String? {
2116+ override static func ignoredProperties() -> [String] {
2117+ return ["imageID", "typingUsers", "timers"]
2121+extension Multichat: Dialog {
2122+ var firstMessage: Message? {
2123+ return messages?.first
2126+ var name: String? {
2130+ func loadImage(into view: UIImageView, completion: (() -> ())? = nil) -> RealmPhotoToken? {
2131+ return image?.load(into: view, completion: completion)
2133+ // func image(completion: @escaping ((UIImage?) -> ())) {
2134+ // if let im = image?.image {
2142+ return id + multichatchatId
2146+class MultiChatUser: Object {
2147+ @objc dynamic var user: User?
2148+ @objc dynamic var invitedBy: User?
2149+ convenience init(_ user: User, invitedBy: User) {
2152+ self.invitedBy = invitedBy
2156+enum MultichatStatus: Int {
2162+class Chat: Object {
2163+ @objc dynamic var user: User? {
2165+ user >>> {userID = $0.id}
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) {
2186+ realmWrite { realm in
2188+ us.messages = Messages.by(id: us.peerID)
2195+ convenience init(user: User) {
2199+ override static func ignoredProperties() -> [String] {
2202+ override class func primaryKey() -> String? {
2207+extension Chat: Dialog {
2208+ var firstMessage: Message? {
2209+ return messages?.first
2212+ var name: String? {
2213+ if let firstName = user?.firstName,
2214+ let lastName = user?.lastName {
2215+ return "\(firstName) \(lastName)"
2221+ func loadImage(into view: UIImageView, completion: (() -> ())? = nil) -> RealmPhotoToken? {
2222+ return user?.avatar?.load(into: view, completion: completion)
2225+ // func image(completion: @escaping ((UIImage?) -> ())) {
2226+ // if let im = user?.avatar?.image {
2242+struct ChatNotificationSettings {
2244+ var disabledUntil: disableDate
2250+ init?(value: Int) {
2257+ self = .date(Date(timeIntervalSince1970: TimeInterval(value)))
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