VPN v2
This commit is contained in:
129
main/unused/AppInfoType.swift
Normal file
129
main/unused/AppInfoType.swift
Normal file
@@ -0,0 +1,129 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
private let fm = FileManager.default
|
||||
private let documentsDir = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
||||
private let bundleInfoDir = documentsDir.appendingPathComponent("bundleInfo", isDirectory:true)
|
||||
|
||||
|
||||
struct AppInfoType : Decodable {
|
||||
var id: String
|
||||
var name: String?
|
||||
var seller: String?
|
||||
var imageURL: URL?
|
||||
private var remoteImgURL: String?
|
||||
private var cache: Bool?
|
||||
private let localJSON: URL
|
||||
private let localImgURL: URL
|
||||
|
||||
static func initWorkingDir() {
|
||||
try? fm.createDirectory(at: bundleInfoDir, withIntermediateDirectories: true, attributes: nil)
|
||||
// print("init dir: \(bundleInfoDir)")
|
||||
}
|
||||
|
||||
init(id: String) {
|
||||
self.id = id
|
||||
if id == "" {
|
||||
name = "–?–"
|
||||
cache = true
|
||||
localJSON = URL(fileURLWithPath: "")
|
||||
localImgURL = localJSON
|
||||
} else {
|
||||
localJSON = bundleInfoDir.appendingPathComponent("\(id).json")
|
||||
localImgURL = bundleInfoDir.appendingPathComponent("\(id).img")
|
||||
reload()
|
||||
}
|
||||
}
|
||||
|
||||
mutating func reload() {
|
||||
if fm.fileExists(atPath: localImgURL.path) {
|
||||
imageURL = localImgURL
|
||||
}
|
||||
guard name == nil, seller == nil,
|
||||
fm.fileExists(atPath: localJSON.path),
|
||||
let attr = try? fm.attributesOfItem(atPath: localJSON.path),
|
||||
attr[FileAttributeKey.size] as! UInt64 > 0 else
|
||||
{
|
||||
// process json only if attributes not set yet,
|
||||
// OR json doesn't exist, OR json is empty
|
||||
return
|
||||
}
|
||||
(name, seller, remoteImgURL) = parseJSON(localJSON)
|
||||
|
||||
if remoteImgURL == nil || imageURL != nil {
|
||||
cache = true
|
||||
}
|
||||
}
|
||||
|
||||
func getImage() -> UIImage? {
|
||||
if let img = imageURL, let data = try? Data(contentsOf: img) {
|
||||
return UIImage(data: data, scale: 2.0)
|
||||
} else if id.hasPrefix("com.apple.") {
|
||||
return appIconApple
|
||||
} else {
|
||||
return appIconUnknown
|
||||
}
|
||||
}
|
||||
|
||||
private func parseJSON(_ location: URL) -> (name: String?, seller: String?, image: String?) {
|
||||
do {
|
||||
let data = try Data.init(contentsOf: location)
|
||||
if
|
||||
let json = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed) as? [String: Any],
|
||||
let resAll = json["results"] as? [Any],
|
||||
let res = resAll.first as? [String: Any]
|
||||
{
|
||||
let name = res["trackName"] as? String // trackCensoredName
|
||||
let seller = res["sellerName"] as? String // artistName
|
||||
let image = res["artworkUrl60"] as? String // artworkUrl100
|
||||
return (name, seller, image)
|
||||
} else if id.hasPrefix("com.apple.") {
|
||||
return (String(id.dropFirst(10)), "Apple Inc.", nil)
|
||||
}
|
||||
} catch {}
|
||||
return (nil, nil, nil)
|
||||
}
|
||||
|
||||
mutating func updateIfNeeded(_ updateClosure: () -> Void) {
|
||||
guard cache == nil,
|
||||
let safeId = id.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
|
||||
return
|
||||
}
|
||||
cache = false // meaning: hasn't downloaded yet, but is about to do
|
||||
// print("downloading \(id)")
|
||||
_ = downloadURL("https://itunes.apple.com/lookup?bundleId=\(safeId)", toFile: localJSON).flatMap{
|
||||
// print("downloading \(id) done.")
|
||||
reload()
|
||||
updateClosure()
|
||||
return downloadURL(remoteImgURL, toFile: localImgURL)
|
||||
}.map{
|
||||
// print("downloading \(id) image done.")
|
||||
reload()
|
||||
updateClosure()
|
||||
}
|
||||
}
|
||||
|
||||
enum NetworkError: Error {
|
||||
case url
|
||||
}
|
||||
|
||||
private func downloadURL(_ urlStr: String?, toFile: URL) -> Result<Void, Error> {
|
||||
guard let urlStr = urlStr, let url = URL(string: urlStr) else {
|
||||
return .failure(NetworkError.url)
|
||||
}
|
||||
var result: Result<Void, Error>!
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
URLSession.shared.downloadTask(with: url) { location, response, error in
|
||||
if let loc = location {
|
||||
try? fm.removeItem(at: toFile)
|
||||
try? fm.moveItem(at: loc, to: toFile)
|
||||
result = .success(())
|
||||
} else {
|
||||
result = .failure(error!)
|
||||
}
|
||||
semaphore.signal()
|
||||
}.resume()
|
||||
_ = semaphore.wait(wallTimeout: .distantFuture)
|
||||
return result
|
||||
}
|
||||
}
|
||||
78
main/unused/BundleIcon.swift
Normal file
78
main/unused/BundleIcon.swift
Normal file
@@ -0,0 +1,78 @@
|
||||
import UIKit
|
||||
|
||||
let appIconApple = generateAppleIcon()
|
||||
let appIconUnknown = generateUnknownIcon()
|
||||
|
||||
func generateAppleIcon() -> UIImage? {
|
||||
let rect = CGRect(x: 0, y: 0, width: 30, height: 30)
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
|
||||
|
||||
// #colorLiteral(red: 0.5843137503, green: 0.8235294223, blue: 0.4196078479, alpha: 1).setFill()
|
||||
// UIBezierPath(roundedRect: rect, cornerRadius: 0).fill()
|
||||
// print("drawing")
|
||||
let fs = 36 as CGFloat
|
||||
let hFont = UIFont.systemFont(ofSize: fs)
|
||||
var attrib = [
|
||||
NSAttributedString.Key.font: hFont,
|
||||
NSAttributedString.Key.foregroundColor: UIColor.gray
|
||||
]
|
||||
|
||||
let str = "" as NSString
|
||||
let actualHeight = str.size(withAttributes: attrib).height
|
||||
attrib[NSAttributedString.Key.font] = hFont.withSize(fs * fs / actualHeight)
|
||||
|
||||
let strW = str.size(withAttributes: attrib).width
|
||||
str.draw(at: CGPoint(x: (rect.size.width - strW) / 2.0, y: -3), withAttributes: attrib)
|
||||
|
||||
let img = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
return img
|
||||
}
|
||||
|
||||
func generateUnknownIcon() -> UIImage? {
|
||||
let rect = CGRect(x: 0, y: 0, width: 30, height: 30)
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()!
|
||||
let lineWidth: CGFloat = 0.5
|
||||
let corner: CGFloat = 6.75
|
||||
let c = corner / CGFloat.pi + lineWidth/2
|
||||
let sz: CGFloat = rect.height
|
||||
let m = sz / 2
|
||||
let r1 = 0.2 * sz, r2 = sqrt(2 * r1 * r1)
|
||||
|
||||
// diagonal
|
||||
context.lineFromTo(x1: c, y1: c, x2: sz-c, y2: sz-c)
|
||||
context.lineFromTo(x1: c, y1: sz-c, x2: sz-c, y2: c)
|
||||
// horizontal
|
||||
context.lineFromTo(x1: 0, y1: m, x2: sz, y2: m)
|
||||
context.lineFromTo(x1: 0, y1: m + r1, x2: sz, y2: m + r1)
|
||||
context.lineFromTo(x1: 0, y1: m - r1, x2: sz, y2: m - r1)
|
||||
// vertical
|
||||
context.lineFromTo(x1: m, y1: 0, x2: m, y2: sz)
|
||||
context.lineFromTo(x1: m + r1, y1: 0, x2: m + r1, y2: sz)
|
||||
context.lineFromTo(x1: m - r1, y1: 0, x2: m - r1, y2: sz)
|
||||
// circles
|
||||
context.addEllipse(in: CGRect(x: m - r1, y: m - r1, width: 2*r1, height: 2*r1))
|
||||
context.addEllipse(in: CGRect(x: m - r2, y: m - r2, width: 2*r2, height: 2*r2))
|
||||
let r3 = CGRect(x: c, y: c, width: sz - 2*c, height: sz - 2*c)
|
||||
context.addEllipse(in: r3)
|
||||
context.addRect(r3)
|
||||
|
||||
UIColor.clear.setFill()
|
||||
UIColor.gray.setStroke()
|
||||
let rounded = UIBezierPath(roundedRect: rect.insetBy(dx: lineWidth/2, dy: lineWidth/2), cornerRadius: corner)
|
||||
rounded.lineWidth = lineWidth
|
||||
rounded.stroke()
|
||||
|
||||
let img = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
return img
|
||||
}
|
||||
|
||||
extension CGContext {
|
||||
func lineFromTo(x1: CGFloat, y1: CGFloat, x2: CGFloat, y2: CGFloat) {
|
||||
self.move(to: CGPoint(x: x1, y: y1))
|
||||
self.addLine(to: CGPoint(x: x2, y: y2))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user