2020-08-27 21:26:12 -07:00
|
|
|
//
|
|
|
|
// FeedsViewController.swift
|
|
|
|
// NewsBlur
|
|
|
|
//
|
|
|
|
// Created by David Sinclair on 2020-08-27.
|
|
|
|
// Copyright © 2020 NewsBlur. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
2021-08-24 21:54:08 -07:00
|
|
|
import StoreKit
|
2020-08-27 21:26:12 -07:00
|
|
|
|
|
|
|
///Sidebar listing all of the feeds.
|
|
|
|
class FeedsViewController: FeedsObjCViewController {
|
2021-08-24 21:54:08 -07:00
|
|
|
struct Keys {
|
|
|
|
static let reviewDate = "datePromptedForReview"
|
|
|
|
static let reviewVersion = "versionPromptedForReview"
|
|
|
|
}
|
|
|
|
|
|
|
|
var appearCount = 0
|
|
|
|
|
|
|
|
lazy var appVersion: String = {
|
|
|
|
let infoDictionaryKey = kCFBundleVersionKey as String
|
|
|
|
|
|
|
|
guard let currentVersion = Bundle.main.object(forInfoDictionaryKey: infoDictionaryKey) as? String else {
|
|
|
|
fatalError("Expected to find a bundle version in the info dictionary")
|
|
|
|
}
|
|
|
|
|
|
|
|
return currentVersion
|
|
|
|
}()
|
|
|
|
|
|
|
|
var datePromptedForReview: Date {
|
|
|
|
get {
|
|
|
|
guard let date = UserDefaults.standard.object(forKey: Keys.reviewDate) as? Date else {
|
|
|
|
let date = Date()
|
|
|
|
UserDefaults.standard.set(date, forKey: Keys.reviewDate)
|
|
|
|
return date
|
|
|
|
}
|
|
|
|
|
|
|
|
return date
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
UserDefaults.standard.set(newValue, forKey: Keys.reviewDate)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var versionPromptedForReview: String {
|
|
|
|
get {
|
|
|
|
return UserDefaults.standard.string(forKey: Keys.reviewVersion) ?? ""
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
UserDefaults.standard.set(newValue, forKey: Keys.reviewVersion)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-02 21:46:26 -07:00
|
|
|
@objc func addSubfolderFeeds() {
|
|
|
|
for folderName in appDelegate.dictFoldersArray {
|
|
|
|
if let folderName = folderName as? String {
|
|
|
|
addSubfolderFeeds(for: folderName)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func addSubfolderFeeds(for folderTitle: String) {
|
|
|
|
guard let parentTitle = self.parentTitle(for: folderTitle) else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-11-30 15:08:30 -06:00
|
|
|
guard let childFeeds = appDelegate.dictFolders[folderTitle] as? [AnyHashable],
|
|
|
|
let parentFeeds = appDelegate.dictFolders[parentTitle] as? [AnyHashable] else {
|
2022-08-02 21:46:26 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-11-30 15:08:30 -06:00
|
|
|
let existingSubfolders = appDelegate.dictSubfolders[parentTitle] as? [AnyHashable] ?? []
|
2022-08-02 21:46:26 -07:00
|
|
|
|
2022-11-30 15:08:30 -06:00
|
|
|
appDelegate.dictFolders[parentTitle] = unique(parentFeeds + childFeeds)
|
|
|
|
appDelegate.dictSubfolders[parentTitle] = unique(existingSubfolders + childFeeds)
|
2022-08-02 21:46:26 -07:00
|
|
|
|
|
|
|
addSubfolderFeeds(for: parentTitle)
|
|
|
|
}
|
|
|
|
|
2022-11-30 15:08:30 -06:00
|
|
|
private func unique(_ array: [AnyHashable]) -> [AnyHashable] {
|
|
|
|
var seen: Set<AnyHashable> = []
|
|
|
|
|
|
|
|
return array.filter { seen.insert($0).inserted }
|
|
|
|
}
|
|
|
|
|
2022-08-02 21:46:26 -07:00
|
|
|
@objc(parentTitleForFolderTitle:) func parentTitle(for folderTitle: String) -> String? {
|
|
|
|
guard let range = folderTitle.range(of: " ▸ ", options: .backwards) else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return String(folderTitle[..<range.lowerBound])
|
|
|
|
}
|
|
|
|
|
|
|
|
@objc(parentTitlesForFolderTitle:) func parentTitles(for folderTitle: String) -> [String] {
|
|
|
|
var parentTitles = [String]()
|
|
|
|
|
|
|
|
guard let parentTitle = parentTitle(for: folderTitle) else {
|
|
|
|
return []
|
|
|
|
}
|
|
|
|
|
|
|
|
parentTitles.append(parentTitle)
|
|
|
|
parentTitles += self.parentTitles(for: parentTitle)
|
|
|
|
|
|
|
|
return parentTitles
|
|
|
|
}
|
|
|
|
|
2021-01-16 19:36:16 -08:00
|
|
|
var loadWorkItem: DispatchWorkItem?
|
2020-08-27 21:26:12 -07:00
|
|
|
|
2021-01-16 19:36:16 -08:00
|
|
|
@objc func loadNotificationStory() {
|
|
|
|
loadWorkItem?.cancel()
|
|
|
|
|
|
|
|
let workItem = DispatchWorkItem { [weak self] in
|
2022-09-25 20:35:46 -06:00
|
|
|
guard let self else {
|
2021-01-16 19:36:16 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-08 17:18:49 -07:00
|
|
|
self.appDelegate.backgroundLoadNotificationStory()
|
2021-01-16 19:36:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
loadWorkItem = workItem
|
2023-05-25 21:47:34 -07:00
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + (isOffline ? .seconds(1) : .milliseconds(200)), execute: workItem)
|
2021-01-16 19:36:16 -08:00
|
|
|
}
|
2021-08-24 21:54:08 -07:00
|
|
|
|
2022-05-25 11:38:13 -06:00
|
|
|
var reloadWorkItem: DispatchWorkItem?
|
|
|
|
|
|
|
|
@objc func deferredUpdateFeedTitlesTable() {
|
|
|
|
reloadWorkItem?.cancel()
|
|
|
|
|
|
|
|
let workItem = DispatchWorkItem { [weak self] in
|
2022-09-25 20:35:46 -06:00
|
|
|
guard let self else {
|
2022-05-25 11:38:13 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
self.updateFeedTitlesTable()
|
|
|
|
self.refreshHeaderCounts()
|
|
|
|
}
|
|
|
|
|
|
|
|
reloadWorkItem = workItem
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: workItem)
|
|
|
|
}
|
|
|
|
|
2021-08-24 21:54:08 -07:00
|
|
|
override func viewDidAppear(_ animated: Bool) {
|
|
|
|
super.viewDidAppear(animated)
|
|
|
|
|
|
|
|
appearCount += 1
|
|
|
|
|
|
|
|
let month: TimeInterval = 60 * 60 * 24 * 30
|
|
|
|
let promptedDate = datePromptedForReview
|
|
|
|
let currentVersion = appVersion
|
|
|
|
let promptedVersion = versionPromptedForReview
|
|
|
|
|
|
|
|
// We only get a few prompts per year, so only ask for a review if gone back to the Feeds list several times, it's been at least a month since the last prompt, and it's a different version.
|
|
|
|
if appearCount >= 5, -promptedDate.timeIntervalSinceNow > month, currentVersion != promptedVersion, let scene = view.window?.windowScene {
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [navigationController] in
|
|
|
|
if navigationController?.topViewController is FeedsViewController {
|
|
|
|
SKStoreReviewController.requestReview(in: scene)
|
|
|
|
self.datePromptedForReview = Date()
|
|
|
|
self.versionPromptedForReview = currentVersion
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-27 21:26:12 -07:00
|
|
|
}
|