@@ -0,0 +1,2224 @@
5+// Created by Ilya Kos on 12/12/16.
6+// Copyright © 2016 Ilya Kos. All rights reserved.
17+typealias Token = String
18+typealias UserID = Int
19+typealias MessageID = Int
20+typealias MultichatID = Int
22+class RealmPhoto: Object {
24+ convenience init(surl: String, id: String) {
26+ self.imageSURL = surl
30+ @objc dynamic var id: String = ""
33+ return imageSURL =>> {URL(string: $0)}
36+ imageSURL = newValue?.absoluteString
39+ @objc dynamic var imageSURL: String? {
41+ if oldValue != imageSURL {
46+ @objc private dynamic var localImageSURL: String? {
48+ if oldValue != localImageSURL {
53+ private var imageCache: UIImage?
55+ convenience init(id: String, surl: String?) {
58+ self.imageSURL = surl
61+ class func by(_ id: String, surl: String?) -> RealmPhoto {
63+ let realm = try Realm()
64+ if let ob = realm.object(ofType: RealmPhoto.self, forPrimaryKey: id) {
65+ if realm.isInWriteTransaction {
66+ surl =>> {ob.imageSURL = $0}
69+ surl =>> {ob.imageSURL = $0}
74+ let ob = RealmPhoto(id: id, surl: surl)
75+ if realm.isInWriteTransaction {
85+ let ob = RealmPhoto(id: id, surl: surl)
90+ override static func primaryKey() -> String? {
94+ override static func ignoredProperties() -> [String] {
95+ return ["imageURL", "imageCache", "completions", "request"]
98+ var completions: [((() -> ()), RealmPhotoToken)] = []
99+ var views: [(UIImageView?, RealmPhotoToken)] = []
100+ var request: DataRequest?
102+ @discardableResult func load(into view: UIImageView, completion: (() -> ())? = nil, error errorClosure: (() -> ())? = nil) -> RealmPhotoToken {
104+ let token = RealmPhotoToken()
106+ func getFromServer() {
108+ let surl = "\(id).png"
109+ if let url = imageURL {
110+ print("getting from network")
111+ request = Alamofire.request(url, method: .get).validate().responseData(queue: userQueue) { (responce) in
113+ switch responce.result {
114+ case .success(let data):
115+ UIImage(data: data) >>> {image in
116+ write(cache: UIImagePNGRepresentation(image), withName: surl) {
117+ realmWrite({ (realm) in
118+ realm.object(ofType: RealmPhoto.self, forPrimaryKey: self.id)?.localImageSURL = surl
121+ self.imageCache = image
122+ DispatchQueue.main.async {
124+ self.views.map { if $0.1.isValid {$0.0?.image = image} }
125+ self.completions.map { if $0.1.isValid { $0.0() } }
126+ self.completions = []
130+ case .failure(let error):
132+ // TODO: Error handling
140+ if let surl = localImageSURL, // TODO: Should probrably get thing from server ???
141+ let url = url(forName: surl) {
142+ Nuke.loadImage(with: url, into: view) { [weak view] (response, fromMemory) in
144+ case .fulfilled(let image):
149+ case .rejected(let error): // TODO: Handle error?
150+ completion >>> {self.completions.append(($0, token))}
151+ self.views.append((view, token))
156+ completion >>> {self.completions.append(($0, token))}
157+ self.views.append((view, token))
164+ // func image(_ completion: @escaping ((UIImage?) -> ())) {
166+ // let surl = "\(id).png"
167+ // if imageCache != nil {
168+ // print("we have caching!")
170+ // imageCache = imageCache ?? (localImageSURL =>> getLocalImage) // TODO: imageCache always seems to be nil... ie always loading from disk for some reason
171+ // if let sImage = imageCache {
172+ // DispatchQueue.main.async { completion(sImage) }
173+ // } else if let url = imageURL {
174+ // print("getting from network")
175+ // Alamofire.request(url, method: .get).validate().responseData(queue: userQueue) { (responce) in
176+ // switch responce.result {
177+ // case .success(let data):
178+ // UIImage(data: data) >>> {image in
179+ // write(cache: UIImagePNGRepresentation(image), withName: surl) {
180+ // DispatchQueue.main.async {
182+ // let realm = try Realm()
183+ // if !realm.isInWriteTransaction {
184+ // try realm.write {
185+ // self.localImageSURL = surl
188+ // self.localImageSURL = surl
193+ // self.imageCache = image
194+ // DispatchQueue.main.async {completion(image)}
196+ // case .failure(let error):
197+ // // TODO: Error handling
205+public class RealmPhotoToken {
206+ public func cancel() {
209+ fileprivate var isValid = true
214+ @objc dynamic var id: UserID = 0
215+ @objc dynamic var firstName: String?
216+ @objc dynamic var lastName: String?
217+ var deactivated: Deactivated? {
219+ return deactivatedStr =>> {Deactivated.init(rawValue: $0)}
222+ deactivatedStr = newValue >>> {$0.rawValue}
225+ @objc private dynamic var deactivatedStr: String?
227+ @objc dynamic var about: String?
228+ @objc dynamic var birthday: Date?
229+ let blacklisted = RealmOptional<Bool>()
230+ let canSendFriendRequest = RealmOptional<Bool>()
231+ let canSendPrivateMessage = RealmOptional<Bool>()
232+ let mutualFriendCount = RealmOptional<Int>()
233+ // TODO: var connections:
234+ @objc dynamic var mobilePhone: String?
235+ @objc dynamic var homePhone: String?
236+ // TODO: var exports
237+ var friendStatus: FriendStatus? {
239+ return friendStatusInt.value =>> {FriendStatus(rawValue: $0)}
242+ friendStatusInt.value = newValue >>> {$0.rawValue}
245+ private let friendStatusInt = RealmOptional<Int>()
246+ let online = RealmOptional<Bool>()
247+ @objc dynamic var avatar: RealmPhoto?
248+ var avatarID: String {
249+ return "user\(id)avatar"
251+ @objc dynamic var photo: RealmPhoto?
252+ var photoID: String {
253+ return "user\(id)photo"
257+ return siteSURL =>> {URL.init(string: $0)}
260+ siteSURL = newValue >>> {$0.absoluteString}
263+ @objc dynamic var siteSURL: String?
264+ @objc dynamic var status: String?
265+ @objc dynamic var lastSeen: Date?
266+ // dynamic var lastUpdated: Date = Date()
267+ let friendCount = RealmOptional<Int>()
269+ convenience init(id: UserID, firstName: String, lastName: String) {
272+ self.firstName = firstName
273+ self.lastName = lastName
274+ // self.lastUpdated = Date()
276+ class func by(id: UserID) -> User {
277+ let realm = try! Realm()
278+ if let us = realm.object(ofType: User.self, forPrimaryKey: id) {
283+ if realm.isInWriteTransaction {
295+ func get(completion: ((User?) -> ())? = nil) {
296+ VK.API.Users.get([VK.Arg.userIDs: "\(id)"]).send(onSuccess: { (response) in
297+ if let json = response.array?.first {
298+ let us = VKData.processUser(json: json)
303+ }, onError: { (error) in
309+ override static func primaryKey() -> String? {
313+ override static func ignoredProperties() -> [String] {
314+ return ["site", "photoID", "avatarID"]
316+ // func update() { lastUpdated = Date() }
318+ // MARK: Hashable override
320+ override var hashValue: Int {
325+class Geolocation: Object {
326+ var geoCoordinates: CLLocation? {
328+ if let long = long.value, let latt = latt.value {
329+ return CLLocation(latitude: latt, longitude: long)
334+ if let latt = newValue?.coordinate.latitude,
335+ let long = newValue?.coordinate.longitude {
336+ self.latt.value = latt
337+ self.long.value = long
339+ self.long.value = nil
340+ self.latt.value = nil
344+ private let latt = RealmOptional<Double>()
345+ private let long = RealmOptional<Double>()
346+ let id = RealmOptional<Int>()
347+ @objc dynamic var title: String?
348+ @objc dynamic var image: RealmPhoto?
349+ var imageID: String {
350+ return "geo_lat\(latt.value ?? 0)_long\(long.value ?? 0)image"
353+ var country: String?
355+ override static func ignoredProperties() -> [String] {
356+ return ["geoCoordinates", "imageID"]
358+ convenience init(long: Double, latt: Double) {
360+ self.long.value = long
361+ self.latt.value = latt
366+class GenericMessage: Object {
367+ @objc dynamic var date = Date() //
368+ @objc dynamic var body = "" //
369+ @objc dynamic var user: User?
371+ var outPhotos: [UIImage] = [] // TODO: ~
373+ @objc dynamic var geolocation: Geolocation?
375+ let attachments = List<RealmMedia>()
376+ let forwardedMessages = List<RealmForwardedMessage>()
377+ //let sentMessageId: MessageID? I DONT KNOW WHY I PUT THIS HERE
379+ // convenience init(body: String) {
382+ // self.out.value = true
384+ // convenience init(image: UIImage) {
386+ // self.outPhotos.append(image)
388+ override static func ignoredProperties() -> [String] {
389+ return ["outPhotos"]
393+class Message: GenericMessage, Comparable, SortedArrayItem {
394+ @objc dynamic var id = 0
395+ let randomID = RealmOptional<MessageID>()
396+ @objc dynamic var read = false
397+ @objc dynamic var replied = false
398+ @objc dynamic var important = false
399+ @objc dynamic var deleted = false
401+ func equal(to message: Message) -> Bool {
402+ // print("\(lhs.id.value) \(rhs.id.value) \(lhs.id.value == rhs.id.value)")
403+ if let a = self.randomID.value,
404+ let b = message.randomID.value {
409+ return self.id == message.id
411+ internal func greater(than message: Message) -> Bool {
412+ return self.id < message.id
415+ static func ==(lhs: Message, rhs: Message) -> Bool {
416+ print("\(lhs.id) \(rhs.id) \(lhs.id == rhs.id)")
417+ return lhs.id == rhs.id
420+ @objc dynamic var out = false
424+ @objc dynamic var photoSURL: String?
425+ let chatID = RealmOptional<MultichatID>()
426+ @objc private dynamic var serviceMessageString: String?
427+ private var serviceMessageUser: User?
428+ private let serviceMessage = RealmOptional<Int>()
430+ var action: ServiceMessageAction? {
432+ func getUser() -> ServiceMessageUser? {
433+ if let user = self.serviceMessageUser {
435+ } else if let email = self.serviceMessageString {
436+ return .email(email)
442+ return serviceMessage.value =>> { service in
449+ return self.serviceMessageString >>> { .create($0) }
451+ return self.serviceMessageString >>> { .titleUpdate($0) }
453+ return getUser() >>> { .inviteUser($0) }
455+ return getUser() >>> { .kickUser($0) }
462+ func set(user: ServiceMessageUser) {
464+ case .user(let use):
465+ self.serviceMessageUser = use
466+ case .email(let str):
467+ self.serviceMessageString = str
471+ serviceMessageString = nil
472+ serviceMessageUser = nil
473+ serviceMessage.value = newValue >>> { new in
479+ case .create(let str):
480+ self.serviceMessageString = str
482+ case .titleUpdate(let str):
483+ self.serviceMessageString = str
485+ case .inviteUser(let user):
488+ case .kickUser(let user):
496+ func get(completion: ((Message?) -> ())? = nil) {
497+ VK.API.Messages.getById([VK.Arg.messageIds: String(id)]).send(onSuccess: { (response) in
498+ if let json = response.array?.first {
499+ let mes = VKData.processMessage(response)
504+ }, onError: { (error) in
507+ // TODO: Implement propperly?
510+ class func by(id: MessageID) -> Message {
511+ let realm = try! Realm()
512+ if let us = realm.object(ofType: Message.self, forPrimaryKey: id) {
524+ override static func primaryKey() -> String? {
528+//func ==(lhs: Message, rhs: Message) -> Bool {
529+// print("\(lhs.id.value) \(rhs.id.value) \(lhs.id.value == rhs.id.value)")
530+// return lhs.id.value == rhs.id.value
532+func <(lhs: Message, rhs: Message) -> Bool {
533+ return lhs.id < rhs.id
536+enum forwardedMessage {
537+ case genericMessage(GenericMessage)
538+ case message(Message)
541+class RealmForwardedMessage: Object {
542+ var value: forwardedMessage? {
544+ if let gm = genericMessage {
545+ return .genericMessage(gm)
546+ } else if let m = message {
554+ if let fm = newValue {
556+ case .genericMessage(let gm):
559+ case .message(let m):
560+ genericMessage = nil
565+ genericMessage = nil
570+ @objc private dynamic var genericMessage: GenericMessage?
571+ @objc private dynamic var message: Message?
573+ var id: MessageID? {
574+ if let m = message {
581+ convenience init(value: forwardedMessage) {
586+ override static func ignoredProperties() -> [String] {
591+//struct Geolocation {
592+// var coordinates: CLLocation
593+// var title: String?
594+// var imageURL: URL? {
596+// return imageSURL =>> {URL.init(string: $0)}
599+// imageSURL = newValue?.absoluteString
602+// var imageSURL: String?
603+// // func image(completion: ((UIImage) -> ())) {
604+// // imageFunc =>> {$0(completion)}
606+// var image: (@escaping ((UIImage) -> ()) -> ())?
608+// var country: String?
609+// init(coordinates: CLLocation, title: String?, imageSURL: String?, image: (@escaping ((UIImage) -> ()) -> ()), city: String?, country: String?) {
610+// self.coordinates = coordinates
611+// self.title = title
612+// self.imageSURL = imageSURL
613+// self.image = image
615+// self.country = country
618+typealias GeolocationID = Int
620+enum Deactivated: String {
621+ case banned = "banned"
622+ case deleted = "deleted"
623+ case normal = "normal"
626+enum FriendStatus: Int {
629+ case requestRecieved
633+enum MessageReadState: Int {
637+enum MessageSendState: Int {
642+enum MultichatNotificationSetting {
647+enum ServiceMessageAction {
648+ case photoUpdate // 0
649+ case photoRemove // 1
650+ case create(String) // 2
651+ case titleUpdate(String) // 3
652+ case inviteUser(ServiceMessageUser) // 4
653+ case kickUser(ServiceMessageUser) // 5
656+enum ServiceMessageUser {
661+typealias MessageChunkID = String
662+class MessageChunk: Object { // message ids go down
663+ subscript(index: Int) -> Message {
664+ return messages[index]
667+ @objc dynamic var id: MessageChunkID = ""
669+ fileprivate let messages = List<Message>()
671+ var firstMessage: Message? {
672+ return messages.first
675+ var lastMessage: Message? {
676+ return messages.last
679+ var firstID: MessageID? {
680+ return firstMessage?.id
683+ var lastID: MessageID? {
684+ return lastMessage?.id
688+ return messages.count
691+ fileprivate func append(message: Message?) {
692+ message >>> {messages.append($0)}
695+ override static func primaryKey() -> String? {
699+ override static func ignoredProperties() -> [String] {
700+ return ["firstMessage", "lastMessage", "firstID", "lastID", "count"]
704+func +=(lhs: MessageChunk, rhs: MessageChunk) {
705+ lhs.messages.append(objectsIn: rhs.messages)
708+/// Returns: true if added. false if was already in list
709+func <~(lhs: MessageChunk?, rhs: Message?) -> Bool {
710+ var out: Bool = false
712+ out = lhs?.messages <~ rhs
716+/// Returns: Indexes of added items
717+func <-(lhs: MessageChunk?, rhs: [Message?]?) -> [Int] {
720+ out = lhs?.messages <- rhs
724+/// Returns: Indexes of added items
725+func <-(lhs: MessageChunk?, rhs: MessageChunk?) -> [Int] {
728+ out = lhs?.messages <- rhs?.messages
734+ case message(Message)
738+typealias MessagesID = Int
739+class Messages: Object {
740+ subscript(ind: Int) -> MessageEntry? {
741+ assert(ind >= 0, "index out of bounds")
742+ if ind >= count || ind < 0 {
747+ while messageChunks[i].count < index {
748+ index -= messageChunks[i].count + 1
751+ if index == messageChunks[i].count {
754+ return .message(messageChunks[i][index])
758+ @objc dynamic var id: MessagesID = 0
760+ @objc fileprivate dynamic var lastChunkID = 0
763+ return messageChunks.endIndex
766+ var first: Message? {
767+ return messageChunks.first?.firstMessage
770+ func count(upToChunk index: Int) -> Int {
772+ for i in 0..<index {
773+ n += messageChunks[i].count + 1
778+ public var count: Int {
779+ var n = messageChunks.count - 1
780+ for chunk in messageChunks {
786+ fileprivate let messageChunks = List<MessageChunk>()
788+ public var chunks: List<MessageChunk> {
789+ return messageChunks
792+ fileprivate enum ChunkIndex {
798+ fileprivate func createChunk(at index: Int = 0) -> MessageChunk {
799+ let chunk = MessageChunk()
800+ realmWrite { (realm) in
801+ chunk.id = "\(id)_\(lastChunkID)"
804+ messageChunks.insert(chunk, at: index)
809+ /// Return nil if there are no chunks
810+ fileprivate func chunkIndex(of message: Message) -> ChunkIndex? {
811+ if messageChunks.count == 0 {
814+ if let first = messageChunks.first?.firstMessage {
815+ if first.greater(than: message) {
819+ for (i, chunk) in messageChunks.enumerated() {
820+ if let lastMessage = chunk.lastMessage { // It should never be nil since a chunk is never empty
821+ if !message.greater(than: lastMessage) { // [ ... | ()] [...] ...
825+ if let firstMessage = chunk.firstMessage { // It should never be nil since a chunk is never empty
826+ if message.greater(than: firstMessage) || message.equal(to: firstMessage) {
836+ return .after(endIndex-1)
840+ override static func primaryKey() -> String? {
844+ override static func ignoredProperties() -> [String] {
848+ class func by(id: MessagesID) -> Messages {
849+ let realm = try! Realm()
850+ if let us = realm.object(ofType: Messages.self, forPrimaryKey: id) {
860+ // MARK: Messages obesrver
862+ static let notificationName: Notification.Name = Notification.Name(rawValue: "MessagesWereModifiedNotificationName")
873+/// Returns: true if added. false if was already in list
874+func <~(lhs: Messages?, rhs: Message?) -> Bool {
875+ var out: Bool = false
879+ if let index = lhs.chunkIndex(of: rhs) {
882+ lhs.messageChunks[i].append(message: rhs)
884+ case .inside(let i):
885+ out = lhs.messageChunks[i] <~ rhs
887+ out = lhs.createChunk(at: 0) <~ rhs
890+ out = lhs.createChunk() <~ rhs
896+/// Only accepts a list of SEQUENTIAL messages. Will silently break if not passed sequentially.
897+/// Returns: Indexes of added items
898+func <-(lhs: Messages?, rhs: [Message?]?) /*-> [Int]*/ {
902+ let rhs = rhs?.flatMap({$0}),
903+ let first = rhs.first,
904+ let last = rhs.last {
906+ var deleted: [Int] = []
907+ var modified: [Int] = []
908+ var added: [Int] = []
909+ if let startI = lhs.chunkIndex(of: first),
910+ let endI = lhs.chunkIndex(of: last) {
913+ print("\t", startI, endI)
915+ case .inside(let i):
925+ case .inside(let i):
933+ start = max(start, 0)
934+ var spacerIndexes = (start+1...end).map({lhs.count(upToChunk: $0) - 1})
935+ // deleted += spacerIndexes
936+ let count = lhs.count(upToChunk: start)
938+ for i in 0..<spacerIndexes.count {
939+ spacerIndexes[i] -= dIndex
940+ deleted.append(spacerIndexes[i])
941+ spacerIndexes[i] -= count
945+ realmWriteWithCompletion { realm, completion in
946+ for x in start+1...end {
947+ print(lhs.chunks.count, x)
948+ lhs.chunks[start] += lhs.chunks[start+1]
949+ realm.delete(lhs.chunks[start+1])
950+ // lhs.chunks.remove(objectAtIndex: start+1)
952+ let chunk = lhs.chunks[start]
953+ addedMs = chunk <- rhs
955+ addedMs.map {$0 + count}
959+ print("after notification", lhs.chunks)
960+ NotificationCenter.default.post(name: Messages.notificationName,
962+ userInfo: [Messages.Changes.added: added,
963+ Messages.Changes.modified: modified,
964+ Messages.Changes.deleted: deleted])
967+ } else { // within one
968+ assert(start == end, "start index is larger than end index!")
969+ realmWriteWithCompletion { _, completion in
971+ added += lhs.createChunk(at: 0) <- rhs
972+ added.append(0) // IDK o[]o[]o []o[]o
974+ added += (lhs.messageChunks[start] <- rhs).map {$0 + lhs.count(upToChunk: start)}
977+ NotificationCenter.default.post(name: Messages.notificationName,
979+ userInfo: [Messages.Changes.added: added,
980+ Messages.Changes.modified: modified,
981+ Messages.Changes.deleted: deleted])
986+ realmWriteWithCompletion { _, completion in
987+ added += lhs.createChunk() <- rhs
989+ NotificationCenter.default.post(name: Messages.notificationName,
991+ userInfo: [Messages.Changes.added: added,
992+ Messages.Changes.modified: modified,
993+ Messages.Changes.deleted: deleted])
1008+ case wall(WallPost)
1009+ case wallReply(WallPostReply)
1010+ case sticker(Sticker)
1013+ case market(Market)
1014+ case marketAlbum(MarketAlbum)
1015+ case graffiti(Document)
1018+ case album(PhotoAlbum)
1019+ var realm: RealmMedia {
1020+ return RealmMedia(value: self)
1024+class RealmMedia: Object {
1025+ @objc private dynamic var photo: Photo?
1026+ @objc private dynamic var video: Video?
1027+ @objc private dynamic var audio: Audio?
1028+ @objc private dynamic var doc: Document?
1029+ @objc private dynamic var wall: WallPost?
1030+ @objc private dynamic var wallReply: WallPostReply?
1031+ @objc private dynamic var sticker: Sticker?
1032+ @objc private dynamic var link: Link?
1033+ @objc private dynamic var gift: Gift?
1034+ @objc private dynamic var market: Market?
1035+ @objc private dynamic var marketAlbum: MarketAlbum?
1036+ @objc private dynamic var graffiti: Document?
1037+ @objc private dynamic var note: Note?
1038+ @objc private dynamic var poll: Poll?
1039+ @objc private dynamic var album: PhotoAlbum?
1041+ var value: Media? {
1043+ if let sureThing = self.photo { return .photo(sureThing) }
1044+ if let sureThing = self.video { return .video(sureThing) }
1045+ if let sureThing = self.audio { return .audio(sureThing) }
1046+ if let sureThing = self.doc { return .doc(sureThing) }
1047+ if let sureThing = self.wall { return .wall(sureThing) }
1048+ if let sureThing = self.wallReply { return .wallReply(sureThing) }
1049+ if let sureThing = self.sticker { return .sticker(sureThing) }
1050+ if let sureThing = self.link { return .link(sureThing) }
1051+ if let sureThing = self.gift { return .gift(sureThing) }
1052+ if let sureThing = self.market { return .market(sureThing) }
1053+ if let sureThing = self.marketAlbum { return .marketAlbum(sureThing) }
1054+ if let sureThing = self.graffiti { return .graffiti(sureThing) }
1055+ if let sureThing = self.note { return .note(sureThing) }
1056+ if let sureThing = self.poll { return .poll(sureThing) }
1057+ if let sureThing = self.album { return .album(sureThing) }
1078+ if let val = newValue {
1080+ case .photo(let foo): photo = foo
1081+ case .video(let foo): video = foo
1082+ case .audio(let foo): audio = foo
1083+ case .doc(let foo): doc = foo
1084+ case .wall(let foo): wall = foo
1085+ case .wallReply(let foo): wallReply = foo
1086+ case .sticker(let foo): sticker = foo
1087+ case .link(let foo): link = foo
1088+ case .gift(let foo): gift = foo
1089+ case .market(let foo): market = foo
1090+ case .marketAlbum(let foo): marketAlbum = foo
1091+ case .graffiti(let foo): graffiti = foo
1092+ case .note(let foo): note = foo
1093+ case .poll(let foo): poll = foo
1094+ case .album(let foo): album = foo
1099+ convenience init(value: Media) {
1105+class Poll: Object {
1106+ @objc dynamic var id: PollID = 0
1107+ @objc dynamic var owner: User?
1108+ @objc dynamic var date: Date?
1109+ @objc dynamic var question: String?
1110+ let votes = RealmOptional<Int>()
1111+ let answerID = RealmOptional<PollAnswerID>()
1112+ let answers = List<PollAnswer>()
1113+ convenience init(id: PollID, owner: User, date: Date, question: String, votes: Int) {
1118+ self.question = question
1119+ self.votes.value = votes
1120+ // self.answerID.value = answerID
1122+ class func by(id: PollID) -> Poll {
1123+ let realm = try! Realm()
1124+ if let us = realm.object(ofType: Poll.self, forPrimaryKey: id) {
1134+ override class func primaryKey() -> String? {
1138+typealias PollID = Int
1140+class PollAnswer: Object {
1141+ @objc dynamic var id: PollAnswerID = 0
1142+ @objc dynamic var body: String = ""
1143+ @objc dynamic var votes: Int = 0
1144+ @objc dynamic var rating: Int = 0
1146+ convenience init(id: PollAnswerID, body: String, votes: Int, rating: Int) {
1151+ self.rating = rating
1154+typealias PollAnswerID = Int
1156+class Note: Object {
1157+ @objc dynamic var id: NoteID = 0
1158+ @objc dynamic var owner: User?
1159+ @objc dynamic var title: String?
1160+ @objc dynamic var body: String?
1161+ @objc dynamic var date: Date?
1164+ return surl =>> {URL(string: $0)}
1167+ surl = newValue >>> {$0.absoluteString}
1170+ @objc dynamic var surl: String?
1171+ let commentCount = RealmOptional<Int>()
1172+ convenience init(id: NoteID, owner: User, title: String, body: String, date: Date, url: URL, commentCount: Int) {
1180+ self.commentCount.value = commentCount
1182+ class func by(id: NoteID) -> Note {
1183+ let realm = try! Realm()
1184+ if let us = realm.object(ofType: Note.self, forPrimaryKey: id) {
1193+ override class func ignoredProperties() -> [String] {
1197+ override class func primaryKey() -> String? {
1201+typealias NoteID = Int
1203+typealias GraffitiID = Int
1204+class Graffiti: Document {
1205+} // Use document.image ?
1207+class Photo: Object {
1208+ @objc dynamic var id: PhotoID = 0
1209+ @objc dynamic var owner: User?
1210+ @objc dynamic var date: Date?
1211+ @objc dynamic var thumbnail: RealmPhoto?
1212+ var thumbnailID: String {
1213+ return "photo\(id)thumbnail"
1215+ @objc dynamic var image: RealmPhoto?
1216+ var imageID: String {
1217+ return "photo\(id)image"
1219+ let width = RealmOptional<Int>()
1220+ let height = RealmOptional<Int>()
1221+ @objc dynamic var accessKey: Key?
1223+ convenience init(id: PhotoID, owner: User, date: Date){
1230+ class func by(id: PhotoID) -> Photo {
1231+ let realm = try! Realm()
1232+ if let us = realm.object(ofType: Photo.self, forPrimaryKey: id) {
1242+ func get(completion: ((Photo?) -> ())? = nil) {
1243+ if let ownerID = owner?.id {
1244+ var ph = "\(ownerID)_\(id)"
1245+ if let key = accessKey {
1246+ ph.append("_\(key)")
1248+ VK.API.Photos.getById([VK.Arg.photos: ph]).send(onSuccess: { (response) in
1249+ if let json = response.array?.first {
1250+ let photo = VKData.processPhoto(json)
1255+ }, onError: { (error) in
1263+ override class func primaryKey() -> String? {
1267+ override static func ignoredProperties() -> [String] {
1268+ return ["thumbnailID", "imageID"]
1272+class PhotoAlbum: Object {
1273+ @objc dynamic var id: PhotoAlbumID = 0
1274+ @objc dynamic var thumb: Photo?
1275+ @objc dynamic var owner: User?
1276+ @objc dynamic var title: String?
1277+ @objc dynamic var albumDescription: String?
1278+ @objc dynamic var dateCreated: Date?
1279+ @objc dynamic var dateUpdated: Date?
1280+ let count = RealmOptional<Int>()
1281+ let photos = List<Photo>()
1282+ convenience init(id: PhotoAlbumID) {
1287+ override class func primaryKey() -> String? {
1290+ class func by(id: PhotoAlbumID) -> PhotoAlbum {
1291+ let realm = try! Realm()
1292+ if let us = realm.object(ofType: PhotoAlbum.self, forPrimaryKey: id) {
1295+ let us = PhotoAlbum()
1303+ // init(id: PhotoAlbumID, thumbID: PhotoID, ownerID: UserID, title: String, dateCreated: Date, dateUpdated: Date, count: Int) {
1305+ // self.thumbID = thumbID
1306+ // self.ownerID = ownerID
1307+ // self.title = title
1308+ // self.dateCreated = dateCreated
1309+ // self.dateUpdated = dateUpdated
1310+ // self.count = count
1314+typealias PhotoID = Int
1315+typealias PhotoAlbumID = Int
1316+typealias Key = String
1318+class WallPost: Object {
1319+ @objc dynamic var id: Int = 0
1320+ @objc dynamic var owner: User?
1321+ @objc dynamic var creator: User?
1322+ @objc dynamic var date: Date?
1323+ @objc dynamic var body: String?
1324+ let commentCount = RealmOptional<Int>()
1325+ let canPostComment = RealmOptional<Bool>()
1326+ let likeCount = RealmOptional<Int>()
1327+ @objc dynamic var liked: Bool = false
1328+ let canLike = RealmOptional<Bool>()
1329+ let repostCount = RealmOptional<Int>()
1330+ let canDelete = RealmOptional<Bool>()
1331+ let didRepost = RealmOptional<Bool>()
1333+ let attachments = List<RealmMedia>()
1334+ @objc dynamic var geo: Geolocation?
1335+ // TODO: let postSource
1336+ @objc dynamic var signed: User?
1337+ @objc dynamic var ownerOfCopy: User?
1338+ @objc dynamic var original: WallPost?
1339+ let historyOfCopy = List<WallPost>()
1340+ let canPin = RealmOptional<Bool>()
1341+ let canEdit = RealmOptional<Bool>()
1342+ let isPinned = RealmOptional<Bool>()
1344+ // 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?) {
1346+ // self.ownerID = ownerID
1347+ // self.creatorID = creatorID
1348+ // self.date = date
1349+ // self.body = body
1350+ // self.commentCount = commentCount
1351+ // self.canPostComment = canPostComment
1352+ // self.likeCount = likeCount
1353+ // self.liked = liked
1354+ // self.canLike = canLike
1355+ // self.repostCount = repostCount
1356+ // self.didRepost = didRepost
1357+ // self.attachments = attachments
1359+ // self.signed = signed
1360+ // self.copyID = copyID
1361+ // self.canDelete = canDelete
1362+ // self.canPin = canPin
1363+ // self.canEdit = canEdit
1364+ // self.isPinned = isPinned
1365+ // self.copyHistory = copyHistory
1366+ // self.copyOwnerID = copyOwnerID
1369+ func get(completion: ((WallPost?) -> ())? = nil) {
1370+ if let ownerID = owner?.id {
1371+ var ph = "\(ownerID)_\(id)"
1372+ // if let key = accessKey {
1373+ // ph.append("_\(key)")
1375+ VK.API.Wall.getById([VK.Arg.posts: ph]).send(onSuccess: { (response) in
1376+ if let json = response.array?.first {
1377+ let photo = VKData.processWallPost(json)
1382+ }, onError: { (error) in
1391+ override class func primaryKey() -> String? {
1395+ class func by(id: UserID) -> WallPost {
1396+ let realm = try! Realm()
1397+ if let us = realm.object(ofType: WallPost.self, forPrimaryKey: id) {
1400+ let us = WallPost()
1408+typealias WallPostID = Int
1410+class WallPostReply: Object {
1411+ @objc dynamic var id: WallPostReplyID = 0
1412+ @objc dynamic var author: User?
1413+ @objc dynamic var wallPost: WallPost?
1414+ @objc dynamic var wallOwner: User?
1415+ @objc dynamic var date: Date?
1416+ @objc dynamic var body: String?
1417+ let likeCount = RealmOptional<Int>()
1418+ let didLike = RealmOptional<Bool>()
1419+ let canLike = RealmOptional<Bool>()
1420+ @objc dynamic var inReplyToUser: User?
1421+ let attachments = List<RealmMedia>()
1422+ @objc dynamic var inReplyToComment: WallPostReply?
1423+ class func by(id: WallPostReplyID) -> WallPostReply {
1424+ let realm = try! Realm()
1425+ if let us = realm.object(ofType: WallPostReply.self, forPrimaryKey: id) {
1428+ let us = WallPostReply()
1435+ override class func primaryKey() -> String? {
1439+typealias WallPostReplyID = Int
1441+class Sticker: Object {
1442+ @objc dynamic var id: StickerID = 0
1443+ @objc dynamic var packID: StickerPackID = 0
1444+ @objc dynamic var image: RealmPhoto?
1445+ var imageID: String {
1446+ return "sticker\(id)image"
1448+ let width = RealmOptional<Int>()
1449+ let height = RealmOptional<Int>()
1451+ convenience init(id: StickerID, packID: StickerPackID, width: Int, height: Int) {
1454+ self.packID = packID
1455+ self.width.value = width
1456+ self.height.value = height
1458+ class func by(id: StickerID) -> Sticker {
1459+ let realm = try! Realm()
1460+ if let us = realm.object(ofType: Sticker.self, forPrimaryKey: id) {
1470+ override class func primaryKey() -> String? {
1473+ override static func ignoredProperties() -> [String] {
1477+typealias StickerID = Int
1478+typealias StickerPackID = Int
1480+class Gift: Object {
1481+ @objc dynamic var id: GiftID = 0
1482+ @objc dynamic var image: RealmPhoto?
1483+ var imageID: String {
1484+ return "gift\(id)image"
1486+ convenience init(id: GiftID, surl: String) {
1489+ self.image = RealmPhoto.by(imageID, surl: surl)
1491+ class func by(id: GiftID) -> Gift {
1492+ let realm = try! Realm()
1493+ if let us = realm.object(ofType: Gift.self, forPrimaryKey: id) {
1503+ override class func primaryKey() -> String? {
1506+ override static func ignoredProperties() -> [String] {
1510+typealias GiftID = Int
1512+class Link: Object {
1515+ return surl =>> {URL(string: $0)}
1518+ @objc dynamic var surl: String = ""
1519+ @objc dynamic var title: String?
1520+ @objc dynamic var caption: String?
1521+ @objc dynamic var linkDescription: String?
1522+ @objc dynamic var photo: Photo?
1523+ let isExternal = RealmOptional<Bool>()
1524+ //var product: Market?
1525+ var rating: Rating? {
1527+ if let stars = ratingStars.value,
1528+ let count = ratingReviewCount.value {
1529+ return Rating(stars: stars, reviewCount: count)
1534+ ratingStars.value = newValue?.stars
1535+ ratingReviewCount.value = newValue?.reviewCount
1538+ private let ratingStars = RealmOptional<Int>()
1539+ private let ratingReviewCount = RealmOptional<Int>()
1540+ //let application: Application?
1541+ var button: LinkButton? {
1543+ if let title = buttonTitle,
1544+ let url = buttonURL {
1545+ return LinkButton(title: title, url: url)
1550+ buttonURL = newValue?.url
1551+ buttonTitle = newValue?.title
1554+ @objc private dynamic var buttonTitle: String?
1555+ private var buttonURL: URL? {
1557+ return buttonSURL =>> {URL(string: $0)}
1560+ buttonSURL = newValue?.absoluteString
1563+ private var buttonSURL: String?
1564+ //let previewURL: URL
1566+ class func by(surl: String) -> Link {
1567+ let realm = try! Realm()
1568+ if let us = realm.object(ofType: Link.self, forPrimaryKey: surl) {
1577+ override class func primaryKey() -> String? {
1580+ override static func ignoredProperties() -> [String] {
1581+ return ["url", "rating", "button", "buttonURL"]
1588+ let reviewCount: Int
1596+class Market: Object {
1597+ @objc dynamic var id: MarketID = 0
1598+ @objc dynamic var owner: User?
1599+ @objc dynamic var title: String?
1600+ @objc dynamic var marketDescription: String?
1601+ let amount = RealmOptional<Int>()
1602+ let price = RealmOptional<Int>()
1603+ let currencyID = RealmOptional<CurrencyID>()
1604+ @objc dynamic var currencyName: String?
1605+ @objc dynamic var priceString: String?
1606+ let categoryID = RealmOptional<MarketCategoryID>()
1607+ @objc dynamic var categoryName: String?
1608+ let sectionID = RealmOptional<MarketSectionID>()
1609+ @objc dynamic var sectionName: String?
1610+ @objc dynamic var image: RealmPhoto?
1611+ var imageID: String {
1612+ return "market\(id)image"
1614+ @objc dynamic var creationDate: Date?
1615+ var availability: MarketAvailability? {
1617+ availabilityInt.value = newValue?.rawValue
1620+ return availabilityInt.value =>> {MarketAvailability(rawValue: $0)}
1623+ private let availabilityInt = RealmOptional<Int>()
1624+ let photos = List<Photo>()
1625+ let canComment = RealmOptional<Bool>()
1626+ let canRepost = RealmOptional<Bool>()
1627+ let likesCount = RealmOptional<Int>()
1628+ let liked = RealmOptional<Bool>()
1630+ class func by(id: MarketID) -> Market {
1631+ let realm = try! Realm()
1632+ if let us = realm.object(ofType: Market.self, forPrimaryKey: id) {
1642+ override class func primaryKey() -> String? {
1645+ override static func ignoredProperties() -> [String] {
1649+typealias CurrencyID = Int
1650+typealias MarketCategoryID = Int
1651+typealias MarketSectionID = Int
1652+enum MarketAvailability: Int {
1653+ case availability = 0
1655+ case notAvailability
1657+typealias MarketID = Int
1659+class MarketAlbum: Object {
1660+ @objc dynamic var id: MarketAlbumID = 0
1661+ @objc dynamic var owner: User?
1662+ @objc dynamic var title: String?
1663+ @objc dynamic var photo: Photo?
1664+ let count = RealmOptional<Int>()
1665+ @objc dynamic var updateTime: Date?
1666+ override class func primaryKey() -> String? {
1670+typealias MarketAlbumID = Int
1672+class Video: Object {
1673+ @objc dynamic var id: VideoID = 0
1674+ @objc dynamic var owner: User?
1675+ @objc dynamic var title: String?
1676+ @objc dynamic var videoDescription: String?
1677+ let duration = RealmOptional<TimeInterval>()
1678+ @objc dynamic var thumbnail: RealmPhoto?
1679+ var thumbnailID: String {
1680+ return "video\(id)thumbnail"
1684+ return playerSURL =>> {URL(string: $0)}
1687+ playerSURL = newValue?.absoluteString
1690+ @objc dynamic var playerSURL: String?
1691+ @objc dynamic var accessKey: String?
1692+ @objc dynamic var isProcessing: Bool = false
1693+ @objc dynamic var isLive: Bool = false
1694+ convenience init(id: VideoID, owner: User, title: String, description: String, duration: TimeInterval) {
1699+ self.videoDescription = description
1700+ self.duration.value = duration
1703+ class func by(id: VideoID) -> Video {
1704+ let realm = try! Realm()
1705+ if let us = realm.object(ofType: Video.self, forPrimaryKey: id) {
1715+ func get(completion: ((Video?) -> ())? = nil) {
1716+ if let peerID = owner?.id {
1717+ var vi = "\(peerID)_\(id)"
1718+ if let key = accessKey {
1719+ vi.append("_\(key)")
1721+ VK.API.Video.get([VK.Arg.videos: vi]).send(onSuccess: { (response) in
1722+ if let json = response["items"].array?.first {
1723+ let video = VKData.processVideo(json)
1728+ }, onError: { (error) in
1736+ override class func primaryKey() -> String? {
1739+ override static func ignoredProperties() -> [String] {
1740+ return ["player", "thumbnailID"]
1743+typealias VideoID = Int
1745+class Audio: Object {
1746+ @objc dynamic var id: AudioID = 0
1747+ @objc dynamic var owner: User?
1748+ @objc dynamic var artist: String?
1749+ @objc dynamic var title: String?
1750+ let duration = RealmOptional<TimeInterval>()
1753+ return surl =>> {URL(string: $0)}
1756+ surl = newValue?.absoluteString
1759+ @objc dynamic var surl: String?
1761+ convenience init(id: AudioID) {
1765+ class func by(id: AudioID) -> Audio {
1766+ let realm = try! Realm()
1767+ if let us = realm.object(ofType: Audio.self, forPrimaryKey: id) {
1777+ override class func primaryKey() -> String? {
1780+ override static func ignoredProperties() -> [String] {
1784+typealias AudioID = Int
1785+typealias LyricID = Int
1786+typealias AudioAlbumID = Int
1787+typealias GenreID = Int
1789+class Document: Object {
1790+ @objc dynamic var id: DocumentID = 0
1791+ @objc dynamic var owner: User?
1792+ @objc dynamic var title: String?
1793+ let size = RealmOptional<Int>()
1794+ @objc dynamic var fileExtension: String?
1797+ return surl =>> {URL(string: $0)}
1800+ surl = newValue?.absoluteString
1803+ @objc dynamic var surl: String?
1804+ @objc dynamic var image: RealmPhoto?
1805+ var imageID: String {
1806+ return "doc\(id)image"
1808+ var type: DocumentType? {
1810+ return typeInt.value =>> {DocumentType(rawValue: $0)}
1813+ typeInt.value = newValue?.rawValue
1816+ private let typeInt = RealmOptional<Int>()
1817+ convenience init(id: DocumentID, owner: User, title: String, size: Int, ext: String, url: URL, type: DocumentType) {
1822+ self.size.value = size
1823+ self.fileExtension = ext
1827+ class func by(id: DocumentID) -> Document {
1828+ let realm = try! Realm()
1829+ if let us = realm.object(ofType: Document.self, forPrimaryKey: id) {
1832+ let us = Document()
1839+ func get(completion: ((Document?) -> ())? = nil) {
1840+ if let ownerID = owner?.id {
1841+ var doc = "\(ownerID)_\(id)"
1842+ // if let key = accessKey {
1843+ // doc.append("_\(key)")
1845+ VK.API.Docs.getById([VK.Arg.docs: doc]).send(onSuccess: { response in
1846+ if let json = response.array?.first {
1847+ let document = VKData.processDocument(json)
1848+ completion?(document)
1852+ }, onError: { (error) in
1860+ override class func primaryKey() -> String? {
1863+ override static func ignoredProperties() -> [String] {
1864+ return ["url", "imageID"]
1867+typealias DocumentID = Int
1868+enum DocumentType: Int {
1880+ var firstMessage: Message? { get }
1881+ var important: Bool { get set }
1882+ var name: String? { get }
1883+ func loadImage(into view: UIImageView, completion: (() -> ())?) -> RealmPhotoToken?
1884+ var messages: Messages? { get }
1885+ var id: Int { get }
1886+ var lastReadMessageID: Int { get set }
1887+ var count: RealmOptional<Int> { get }
1888+ var notificationSettings: RealmNotificatonSettings? { get set }
1889+ var peerID: Int { get }
1892+func dialog(for id: DialogID) -> Dialog {
1893+ if id > multichatchatId { // multichat
1894+ let chat = Multichat.by(id: id - multichatchatId)
1897+ //} else if id < 0 { // Pablic
1899+ } else { // Normal user
1900+ let chat = Chat.by(user: User.by(id: id))
1905+// For name conflicts
1906+func dialogFor(_ id: DialogID) -> Dialog {
1907+ return dialog(for: id)
1910+class RealmDialog: Object, Comparable {
1912+ // TODO: Remove these two
1913+ @objc dynamic var dateLastSent: Date?
1914+ /// Number of times a message has been sent in the dateLastSent second
1915+ @objc dynamic var dateSentNumber = 0
1917+ var value: Dialog? {
1919+ return dialog(for: id)
1924+ return value?.peerID
1927+ @objc dynamic var id: DialogID = 0
1929+ @objc dynamic var date: Date?
1931+ class func by(dialog: Dialog) -> RealmDialog {
1932+ return RealmDialog.by(peerID: dialog.peerID)
1935+ class func by(peerID: Int) -> RealmDialog {
1936+ if let dialog = (try? Realm())?.object(ofType: RealmDialog.self, forPrimaryKey: peerID) {
1939+ let dialog = RealmDialog()
1941+ realmWrite({ (realm) in
1948+ override class func primaryKey() -> String? {
1951+ override static func ignoredProperties() -> [String] {
1952+ return ["value", "peerID"]
1955+func ==(lhs: RealmDialog, rhs: RealmDialog) -> Bool {
1956+ return lhs.date == rhs.date
1958+func <(lhs: RealmDialog, rhs: RealmDialog) -> Bool {
1959+ if let l = lhs.date,
1966+typealias DialogID = Int
1968+//func ==(lhs: Dialog, rhs: Dialog) -> Bool {
1969+// return lhs.date == rhs.date
1971+//func <(lhs: Dialog, rhs: Dialog) -> Bool {
1972+// return lhs.date < rhs.date
1975+class RealmNotificatonSettings: Object {
1976+ var value: ChatNotificationSettings? {
1978+ if let sound = notiSound.value,
1979+ let never = notiDateNever.value {
1981+ return ChatNotificationSettings(sound: sound, disabledUntil: .never)
1983+ return notiDate >>> {ChatNotificationSettings(sound: sound, disabledUntil: .date($0))}
1989+ notiSound.value = newValue?.sound
1990+ if let newV = newValue {
1991+ switch newV.disabledUntil {
1992+ case .date(let date):
1994+ notiDateNever.value = false
1996+ notiDateNever.value = true
2002+ private let notiSound = RealmOptional<Bool>()
2003+ private let notiDateNever = RealmOptional<Bool>()
2004+ @objc private dynamic var notiDate: Date?
2005+ convenience init(value: ChatNotificationSettings?) {
2011+class Multichat: Object {
2012+ @objc dynamic var id: MultichatID = 0
2013+ @objc dynamic var admin: User?
2014+ var timers: [UserID: Timer] = [:]
2015+ var typingUsers: Set<User> = []
2016+ @objc dynamic var title: String?
2017+ let users = List<MultiChatUser>()
2018+ @objc dynamic var messages: Messages?
2019+ // let messages = List<Message>()
2020+ @objc dynamic var lastReadMessageID = 0
2021+ @objc dynamic var important = false
2022+ @objc dynamic var answered = false
2023+ @objc dynamic var date = Date()
2024+ let count = RealmOptional<Int>()
2025+ @objc dynamic var image: RealmPhoto?
2026+ var imageID: String {
2027+ return "mchat\(id)image"
2029+ let attachments = List<RealmMedia>()
2031+ @objc dynamic var notificationSettings: RealmNotificatonSettings?
2033+ var participationStatus: MultichatStatus? {
2035+ return participationStatusInt.value =>> {MultichatStatus(rawValue: $0)}
2038+ participationStatusInt.value = newValue?.rawValue
2041+ private let participationStatusInt = RealmOptional<Int>()
2043+ // convenience init(id: MultichatID, adminID: UserID, title: String, userIDs: [(user: UserID, invitedBy: UserID)]?, notificationSettings: MultichatNotificationSettings?, participationStatus: MultichatStatus?) {
2045+ // self.adminID = adminID
2046+ // self.title = title
2047+ // self.userIDs = userIDs
2048+ // self.notificationSetting = notificationSettings
2049+ // self.participationStatus = participationStatus
2051+ class func by(id: MultichatID) -> Multichat {
2052+ let realm = try! Realm()
2053+ if let us = realm.object(ofType: Multichat.self, forPrimaryKey: id) {
2056+ VkServices.getMultichat(for: id)
2057+ let us = Multichat()
2058+ realmWrite { realm in
2060+ us.messages = Messages.by(id: us.peerID)
2067+ override class func primaryKey() -> String? {
2070+ override static func ignoredProperties() -> [String] {
2071+ return ["imageID", "typingUsers", "timers"]
2075+extension Multichat: Dialog {
2076+ var firstMessage: Message? {
2077+ return messages?.first
2080+ var name: String? {
2084+ func loadImage(into view: UIImageView, completion: (() -> ())? = nil) -> RealmPhotoToken? {
2085+ return image?.load(into: view, completion: completion)
2087+ // func image(completion: @escaping ((UIImage?) -> ())) {
2088+ // if let im = image?.image {
2096+ return id + multichatchatId
2100+class MultiChatUser: Object {
2101+ @objc dynamic var user: User?
2102+ @objc dynamic var invitedBy: User?
2103+ convenience init(_ user: User, invitedBy: User) {
2106+ self.invitedBy = invitedBy
2110+enum MultichatStatus: Int {
2116+class Chat: Object {
2117+ @objc dynamic var user: User? {
2119+ user >>> {userID = $0.id}
2123+ @objc dynamic var date = Date()
2124+ @objc dynamic var userID = 0
2125+ @objc dynamic var isTyping = false
2126+ @objc dynamic var lastReadMessageID = 0
2127+ let count = RealmOptional<Int>()
2128+ @objc dynamic var messages: Messages?
2129+ // let messages = List<Message>()
2130+ @objc dynamic var important = false
2131+ @objc dynamic var answered = false
2132+ let attachments = List<RealmMedia>()
2133+ @objc dynamic var notificationSettings: RealmNotificatonSettings?
2134+ class func by(user: User) -> Chat {
2135+ let realm = try! Realm()
2136+ if let us = realm.object(ofType: Chat.self, forPrimaryKey: user.id) {
2140+ realmWrite { realm in
2142+ us.messages = Messages.by(id: us.peerID)
2149+ convenience init(user: User) {
2153+ override static func ignoredProperties() -> [String] {
2156+ override class func primaryKey() -> String? {
2161+extension Chat: Dialog {
2162+ var firstMessage: Message? {
2163+ return messages?.first
2166+ var name: String? {
2167+ if let firstName = user?.firstName,
2168+ let lastName = user?.lastName {
2169+ return "\(firstName) \(lastName)"
2175+ func loadImage(into view: UIImageView, completion: (() -> ())? = nil) -> RealmPhotoToken? {
2176+ return user?.avatar?.load(into: view, completion: completion)
2179+ // func image(completion: @escaping ((UIImage?) -> ())) {
2180+ // if let im = user?.avatar?.image {
2196+struct ChatNotificationSettings {
2198+ var disabledUntil: disableDate
2204+ init?(value: Int) {
2211+ self = .date(Date(timeIntervalSince1970: TimeInterval(value)))
2216+func isPhoneNumber(_ phone: String) -> Bool {
2217+ let nums = "1234567890".characters
2218+ let f002 = phone.characters.map{nums.contains($0) ? 1 : 0}
2219+ let foo1 = Double(sum(acc: 0, arr: f002))
2220+ let foo = foo1/Double(phone.characters.count)
2221+ return foo >= 0.4 ? true : false