2019-12-20 19:09:20 -08:00
|
|
|
//
|
|
|
|
// WidgetStory.swift
|
|
|
|
// Widget Extension
|
|
|
|
//
|
|
|
|
// Created by David Sinclair on 2019-11-29.
|
|
|
|
// Copyright © 2019 NewsBlur. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
|
|
|
|
/// A story to display in the widget.
|
|
|
|
struct Story: Codable, Identifiable {
|
|
|
|
/// The version number.
|
|
|
|
let version = 1
|
|
|
|
|
|
|
|
/// The story hash.
|
|
|
|
let id: String
|
|
|
|
|
|
|
|
/// The feed ID.
|
|
|
|
let feed: String
|
|
|
|
|
|
|
|
/// The date and/or time as a string.
|
|
|
|
let date: String
|
|
|
|
|
|
|
|
/// The author of the story.
|
|
|
|
let author: String
|
|
|
|
|
|
|
|
/// The title of the story.
|
|
|
|
let title: String
|
|
|
|
|
|
|
|
/// The content of the story.
|
|
|
|
let content: String
|
|
|
|
|
|
|
|
/// The URL of the image, or `nil` if none.
|
|
|
|
let imageURL: URL?
|
|
|
|
|
|
|
|
/// Keys for the dictionary representation.
|
|
|
|
struct DictionaryKeys {
|
|
|
|
static let id = "story_hash"
|
|
|
|
static let feed = "story_feed_id"
|
|
|
|
static let date = "short_parsed_date"
|
|
|
|
static let author = "story_authors"
|
|
|
|
static let title = "story_title"
|
|
|
|
static let content = "story_content"
|
2020-03-10 20:47:38 -07:00
|
|
|
static let imageURLs = "image_urls"
|
|
|
|
static let secureImageURLs = "secure_image_thumbnails"
|
2019-12-20 19:09:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Initializer from a dictionary.
|
|
|
|
///
|
|
|
|
/// - Parameter dictionary: Dictionary from the server.
|
|
|
|
init(from dictionary: [String : Any]) {
|
|
|
|
id = dictionary[DictionaryKeys.id] as? String ?? ""
|
|
|
|
feed = dictionary[DictionaryKeys.feed] as? String ?? "\(dictionary[DictionaryKeys.feed] as? Int ?? 0)"
|
|
|
|
date = dictionary[DictionaryKeys.date] as? String ?? ""
|
|
|
|
author = dictionary[DictionaryKeys.author] as? String ?? ""
|
|
|
|
title = dictionary[DictionaryKeys.title] as? String ?? ""
|
|
|
|
content = dictionary[DictionaryKeys.content] as? String ?? ""
|
|
|
|
|
2020-03-10 20:47:38 -07:00
|
|
|
if let imageURLs = dictionary[DictionaryKeys.imageURLs] as? [String], let first = imageURLs.first, let secureImages = dictionary[DictionaryKeys.secureImageURLs] as? [String : String], let url = secureImages[first] {
|
|
|
|
imageURL = URL(string: url)
|
2019-12-20 19:09:20 -08:00
|
|
|
} else {
|
|
|
|
imageURL = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Keys for the codable representation.
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
|
|
case version = "version"
|
|
|
|
case id = "id"
|
|
|
|
case feed = "feed"
|
|
|
|
case date = "date"
|
|
|
|
case author = "author"
|
|
|
|
case title = "title"
|
|
|
|
case content = "content"
|
|
|
|
case imageURL = "imageURL"
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Initializer to load from the JSON data.
|
|
|
|
///
|
|
|
|
/// - Parameter decoder: The decoder from which to read data.
|
|
|
|
/// - Throws: An error if the data is invalid.
|
|
|
|
init(from decoder: Decoder) throws {
|
|
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
|
|
|
|
|
|
id = try container.decode(String.self, forKey: .id)
|
|
|
|
feed = try container.decode(String.self, forKey: .feed)
|
|
|
|
date = try container.decode(String.self, forKey: .date)
|
|
|
|
author = try container.decode(String.self, forKey: .author)
|
|
|
|
title = try container.decode(String.self, forKey: .title)
|
|
|
|
content = try container.decode(String.self, forKey: .content)
|
|
|
|
imageURL = try container.decodeIfPresent(URL.self, forKey: .imageURL)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Encodes the story into the given encoder.
|
|
|
|
///
|
|
|
|
/// - Parameter encoder: The encoder to which to write data.
|
|
|
|
/// - Throws: An error if the data is invalid.
|
|
|
|
func encode(to encoder: Encoder) throws {
|
|
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
|
|
|
|
|
|
try container.encode(version, forKey: .version)
|
|
|
|
try container.encode(id, forKey: .id)
|
|
|
|
try container.encode(feed, forKey: .feed)
|
|
|
|
try container.encode(date, forKey: .date)
|
|
|
|
try container.encode(author, forKey: .author)
|
|
|
|
try container.encode(title, forKey: .title)
|
|
|
|
try container.encode(content, forKey: .content)
|
|
|
|
try container.encodeIfPresent(imageURL, forKey: .imageURL)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension Story: Equatable {
|
|
|
|
static func ==(lhs: Story, rhs: Story) -> Bool {
|
|
|
|
return lhs.id == rhs.id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension Story: CustomStringConvertible {
|
|
|
|
var description: String {
|
|
|
|
return "Story \(title) by \(author) (\(id))"
|
|
|
|
}
|
|
|
|
}
|