Untitled

mail@pastecode.io avatar
unknown
swift
2 years ago
8.8 kB
4
Indexable
Never
import UIKit

struct VKNews {
    private var items: [VKNew]
    private var profiles: [VKUser]
    private var groups: [VKGroup]
    let nextFrom: String
    
    init?(){
        self.items = []
        self.profiles = []
        self.groups = []
        self.nextFrom = ""
    }
    
    func news() -> [VKNew]{
        var news: [VKNew] = []
        self.items.forEach{ new in
            switch new.sourceType{
            case .profile:
                let profile = self.profiles.first{
                    $0.id == new.sourceID
                }
                let tempName = profile?.name ?? ""
                let tempURL = profile?.photoURL
                guard var tempNew = VKNew(new: new, sourceName: tempName, photoUrl: tempURL)
                else {return}
                tempNew.buildCellsArray()
                news.append(tempNew)
            case .group:
                let group = self.groups.first{
                    $0.id == new.sourceID
                }
                let tempName = group?.name ?? ""
                let tempURL = group?.photoURL
                guard var tempNew = VKNew(new: new, sourceName: tempName, photoUrl: tempURL)
                else {return}
                tempNew.buildCellsArray()
                news.append(tempNew)
            }
        }
        return news
    }
}

struct VKNew {
    let text: String
    var shortText: String?
    var isShortText: Bool?
    
    var photos: [VKNewsPhoto] = []
    var docs: [VKNewsDoc] = []
    private var cellsCounter: [(VKBlocksType,Int)] = []
    
    let date: Double
    let stringDate: String

    let sourceID: Int
    let sourceType: SourceType
    
    var sourceName = ""
    var photoUrl: URL? = nil
    
    let likesCount: Int
    let isLiked: Bool
    let repostsCount: Int
    let isReposted: Bool
    let viewsCount: Int
    
    init?(new: VKNew, sourceName: String, photoUrl: URL?){
        self = new
        self.sourceName = sourceName
        self.photoUrl = photoUrl
        if self.text.count > 200 {
            shortText = String(text.prefix(200)) + "..."
            isShortText = true
        }
    }
    
    mutating func buildCellsArray(){
        if !text.isEmpty{
            cellsCounter.append((.text,0))
        }
        if !photos.isEmpty{
            cellsCounter.append((.photos,0))
        }
        for i in (0..<docs.count){
            cellsCounter.append((.docs,i))
        }
    }
    
    func returnCellsCounter() -> [(VKBlocksType,Int)] {
        return cellsCounter
    }
}

enum VKBlocksType{
    case text
    case photos
    case docs
}

struct VKNewsPhoto {
    let sizes: [VKPhotoSize]
    var aspectRatio: Double? {
        guard
            let size = self.sizes.first,
            let height = size.height,
            let width = size.width
        else { return nil }
        return Double(height) / Double(width)
    }
}

struct VKNewsDoc {
    let title: String
    let size: Int
    let url: URL?
}

extension VKNews: Decodable {
    enum CodingKeys: String, CodingKey{
        case items
        case profiles
        case groups
        case nextFrom = "next_from"
    }
}

extension VKNew: Decodable{
    enum NewCodingKeys: String, CodingKey{
        case text
        case attachments
        case date
        case sourceID = "source_id"
        case likes
        case reposts
        case views
    }
    enum LikesCodingKeys: String, CodingKey{
        case count
        case userLikes = "user_likes"
    }
    enum RepostsCodingKeys: String, CodingKey{
        case count
        case userReposted = "user_reposted"
    }
    enum ViewsCodingKeys: String, CodingKey{
        case count
    }
    
    enum AttachmentsCodingKeys: String, CodingKey{
        case type
        case photo
        case doc
    }
    
    enum DocsCodingKeys: String, CodingKey{
        case title
        case size
        case url
    }
    
    enum PhotosCodingKeys: String, CodingKey{
        case sizes
    }
    
    enum SizesCodingKeys: String, CodingKey{
        case type
        case url
        case height
        case width
    }
    
    
    enum SourceType: String{
        case profile = "profile"
        case group = "group"
        
        init?(_ param: String){
            switch param{
            case "profile":
                self = .profile
            default:
                self = .group
            }
        }
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: NewCodingKeys.self)
        self.text = try container.decode(String.self, forKey: .text)
        
        if container.contains(.attachments) {
            var attachmentsContainer = try container.nestedUnkeyedContainer(forKey: .attachments)
            while(!attachmentsContainer.isAtEnd){
                let attachmentContainer = try attachmentsContainer.nestedContainer(keyedBy: AttachmentsCodingKeys.self)
                let type = try attachmentContainer.decode(String.self, forKey: .type)
                switch type{
                case "photo":
                    let photoContainer = try attachmentContainer.nestedContainer(keyedBy: PhotosCodingKeys.self, forKey: .photo)
                    
                    var sizesContainer = try photoContainer.nestedUnkeyedContainer(forKey: .sizes)
                    var tempSizes: [VKPhotoSize] = []
                    while(!sizesContainer.isAtEnd){
                        let sizeContainer = try sizesContainer.nestedContainer(keyedBy: SizesCodingKeys.self)
                        let tempUrlString = try sizeContainer.decode(
                            String.self,
                            forKey: .url)
                        let url = URL(string: tempUrlString)
                        let type = try sizeContainer.decode(String.self, forKey: .type)
                        let tempHeight, tempWidth: Int?
                        if sizeContainer.contains(.height) {
                            tempHeight = try sizeContainer.decode(
                                Int.self,
                                forKey: .height)
                            tempWidth = try sizeContainer.decode(
                                Int.self,
                                forKey: .width)
                        } else {
                            tempHeight = nil
                            tempWidth = nil
                        }
                        tempSizes.append(
                            VKPhotoSize(
                                url: url,
                                sizeType: type,
                                height: tempHeight,
                                width: tempWidth))
                    }
                    self.photos.append(VKNewsPhoto(sizes: tempSizes))
                case "doc":
                    let docContainer = try attachmentContainer.nestedContainer(keyedBy: DocsCodingKeys.self, forKey: .doc)
                    let title = try docContainer.decode(String.self, forKey: .title)
                    let size = try docContainer.decode(Int.self, forKey: .size)
                    let tempUrl = try docContainer.decode(String.self, forKey: .url)
                    let url = URL(string: tempUrl)
                    let doc = VKNewsDoc(title: title, size: size, url: url)
                    self.docs.append(doc)
                default:
                    continue
                }
            }
        }
        
        self.date = try container.decode(Double.self, forKey: .date)
        self.stringDate = self.date.date()
        let tempSourceID = try container.decode(Int.self, forKey: .sourceID)
        self.sourceID = abs(tempSourceID)
        self.sourceType = (tempSourceID > 0) ? SourceType.profile : SourceType.group
        
        
        
        let likesContainer = try container.nestedContainer(keyedBy: LikesCodingKeys.self, forKey: .likes)
        self.likesCount = try likesContainer.decode(Int.self, forKey: .count)
        let tempIsLiked = try likesContainer.decode(Int.self, forKey: .userLikes)
        self.isLiked = Bool(truncating: NSNumber(value: tempIsLiked))
        
        let repostsContainer = try container.nestedContainer(keyedBy: RepostsCodingKeys.self, forKey: .reposts)
        self.repostsCount = try repostsContainer.decode(Int.self, forKey: .count)
        let tempIsReposted = try repostsContainer.decode(Int.self, forKey: .userReposted)
        self.isReposted = Bool(truncating: NSNumber(value: tempIsReposted))
        
        if container.contains(.views){
            let viewsContainer = try container.nestedContainer(keyedBy: ViewsCodingKeys.self, forKey: .views)
            self.viewsCount = try viewsContainer.decode(Int.self, forKey: .count)
        } else {
            self.viewsCount = 0
        }
    }
}