diff --git a/App/AppDelegate.swift b/App/AppDelegate.swift
index fb15fee1..8349f6a9 100644
--- a/App/AppDelegate.swift
+++ b/App/AppDelegate.swift
@@ -8,6 +8,7 @@
import UIKit
import SwinjectStoryboard
+import Nuke
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -22,6 +23,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if ProcessInfo.processInfo.arguments.contains("skipAnimations") {
UIView.setAnimationsEnabled(false)
}
+ if ProcessInfo.processInfo.arguments.contains("darkMode") {
+ window?.overrideUserInterfaceStyle = .dark
+ }
// setup window and entry point
window = UIWindow()
@@ -33,10 +37,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
window?.tintColor = AppTheme.default.appTintColor
window?.makeKeyAndVisible()
- if ProcessInfo.processInfo.arguments.contains("darkMode") {
- window?.overrideUserInterfaceStyle = .dark
- }
-
// setup NavigationService
navigationService = SwinjectStoryboard.getService()
navigationService?.mainSplitViewController = mainSplitViewController
@@ -47,6 +47,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// init default settings
UserDefaults.standard.registerDefaults()
+
+ // setup Nuke
+ DataLoader.sharedUrlCache.diskCapacity = 1024 * 1024 * 100 // 100MB
}
func application(
diff --git a/App/Comments/CommentsViewController.swift b/App/Comments/CommentsViewController.swift
index dd1f6191..1696c63e 100644
--- a/App/Comments/CommentsViewController.swift
+++ b/App/Comments/CommentsViewController.swift
@@ -36,7 +36,7 @@ class CommentsViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
- setupCollectionView()
+ setupRefreshControl()
load()
}
@@ -44,6 +44,16 @@ class CommentsViewController: UITableViewController {
tearDownHandoff()
}
+ private func setupRefreshControl() {
+ let refreshControl = UIRefreshControl()
+ refreshControl.addTarget(
+ self,
+ action: #selector(load),
+ for: .valueChanged
+ )
+ self.refreshControl = refreshControl
+ }
+
@objc private func load(showSpinner: Bool = true) {
if showSpinner {
tableView.backgroundView = TableViewBackgroundView.loadingBackgroundView()
@@ -250,8 +260,18 @@ extension CommentsViewController {
voteAction()
}
+ let share = UIAction(
+ title: "Share",
+ image: UIImage(systemName: "square.and.arrow.up"),
+ identifier: UIAction.Identifier(rawValue: "share.comment")
+ ) { [weak self] _ in
+ self?.shareComment(at: indexPath)
+ }
+
let voteMenu = upvoted ? unvote : upvote
- return UIMenu(title: "", image: nil, identifier: nil, children: [voteMenu])
+ let shareMenu = UIMenu(title: "", options: .displayInline, children: [share])
+
+ return UIMenu(title: "", image: nil, identifier: nil, children: [voteMenu, shareMenu])
}
}
@@ -350,7 +370,7 @@ extension CommentsViewController: SwipeTableViewCellDelegate {
)
case (.right, 1):
- return [collapseAction(), shareAction()]
+ return [collapseAction()]
case (.left, 1):
let comment = commentsController.visibleComments[indexPath.row]
@@ -366,28 +386,16 @@ extension CommentsViewController: SwipeTableViewCellDelegate {
}
}
- private func shareAction() -> SwipeAction {
- let shareAction = SwipeAction(style: .default, title: "Share") { [weak self] _, indexPath in
- guard let strongSelf = self else {
- return
- }
- let comment = strongSelf.commentsController.visibleComments[indexPath.row]
- let url = comment.hackerNewsURL
- let activityViewController = UIActivityViewController(
- activityItems: [url],
- applicationActivities: nil
- )
- let cell = strongSelf.tableView.cellForRow(at: indexPath)
- activityViewController.popoverPresentationController?.sourceView = cell
- strongSelf.present(activityViewController, animated: true, completion: nil)
- }
- shareAction.backgroundColor = .systemGreen
- shareAction.textColor = .white
-
- let iconImage = UIImage(systemName: "square.and.arrow.up")!.withTintColor(.white)
- shareAction.image = iconImage
-
- return shareAction
+ private func shareComment(at indexPath: IndexPath) {
+ let comment = self.commentsController.visibleComments[indexPath.row]
+ let url = comment.hackerNewsURL
+ let activityViewController = UIActivityViewController(
+ activityItems: [url],
+ applicationActivities: nil
+ )
+ let cell = self.tableView.cellForRow(at: indexPath)
+ activityViewController.popoverPresentationController?.sourceView = cell
+ self.present(activityViewController, animated: true, completion: nil)
}
private func collapseAction() -> SwipeAction {
@@ -483,17 +491,6 @@ extension CommentsViewController: CommentDelegate {
// MARK: - Handoff
extension CommentsViewController {
-
- private func setupCollectionView() {
- let refreshControl = UIRefreshControl()
- refreshControl.addTarget(
- self,
- action: #selector(load),
- for: .valueChanged
- )
- self.refreshControl = refreshControl
- }
-
private func setupHandoff(with post: Post?, activityType: ActivityType) {
guard let post = post else {
return
diff --git a/App/Services/OnboardingService.swift b/App/Services/OnboardingService.swift
index 8111f90c..d99a9440 100644
--- a/App/Services/OnboardingService.swift
+++ b/App/Services/OnboardingService.swift
@@ -58,12 +58,22 @@ enum OnboardingService {
}
private static func items() -> [WhatsNew.Item] {
- let defaultBrowserItem = WhatsNew.Item(
- title: "Disable swipe gestures",
- subtitle: "Added a setting to disable all swipe gestures, you can long tap for a menu instead. Thanks to @ballwood for the contribution.",
- image: UIImage(systemName: "hand.draw.fill")
+ let pullToRefreshItem = WhatsNew.Item(
+ title: "Pull to refresh comments",
+ subtitle: "Thanks @ballwood.",
+ image: UIImage(systemName: "arrow.clockwise")
)
- return [defaultBrowserItem]
+ let shareCommentItem = WhatsNew.Item(
+ title: "Share comments",
+ subtitle: "Long press on a comment to share a direct link.",
+ image: UIImage(systemName: "bubble.left")
+ )
+ let bugfixesItem = WhatsNew.Item(
+ title: "Fixes and improvements",
+ subtitle: "Feedback emails work with third party email apps.\n\nThumbnail cache size limited to 100MB.",
+ image: UIImage(systemName: "checkmark.seal")
+ )
+ return [pullToRefreshItem, shareCommentItem, bugfixesItem]
}
}
diff --git a/App/Settings/SettingsViewController.swift b/App/Settings/SettingsViewController.swift
index 351bf0f9..f7e7c0ee 100644
--- a/App/Settings/SettingsViewController.swift
+++ b/App/Settings/SettingsViewController.swift
@@ -118,14 +118,24 @@ extension SettingsViewController {
}
private func sendFeedbackEmail() {
+ let appVersion = self.appVersion() ?? ""
+ let emailAddress = "weiran@zhang.me.uk"
+ let subject = "Feedback for Hackers \(appVersion)"
+
if MFMailComposeViewController.canSendMail() {
- let appVersion = self.appVersion() ?? ""
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
- mail.setToRecipients(["weiran@zhang.me.uk"])
- mail.setSubject("Feedback for Hackers \(appVersion)")
+ mail.setToRecipients([emailAddress])
+ mail.setSubject(subject)
mail.setMessageBody("", isHTML: true)
present(mail, animated: true)
+ } else {
+ let mailtoString = "mailto:\(emailAddress)?subject=\(subject)"
+ .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
+ let mailtoURL = URL(string: mailtoString)!
+ if UIApplication.shared.canOpenURL(mailtoURL) {
+ UIApplication.shared.open(mailtoURL, options: [:])
+ }
}
}
diff --git a/Extensions/HackersActionExtension/Info.plist b/Extensions/HackersActionExtension/Info.plist
index 6afdcb4b..7888ba05 100644
--- a/Extensions/HackersActionExtension/Info.plist
+++ b/Extensions/HackersActionExtension/Info.plist
@@ -17,9 +17,9 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 4.6.3
+ 4.6.4
CFBundleVersion
- 105
+ 106
NSExtension
NSExtensionAttributes
diff --git a/Extensions/HackersShareExtension/Info.plist b/Extensions/HackersShareExtension/Info.plist
index 22effe99..220dff30 100644
--- a/Extensions/HackersShareExtension/Info.plist
+++ b/Extensions/HackersShareExtension/Info.plist
@@ -17,9 +17,9 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 4.6.3
+ 4.6.4
CFBundleVersion
- 105
+ 106
NSExtension
NSExtensionAttributes
diff --git a/Hackers.xcodeproj/project.pbxproj b/Hackers.xcodeproj/project.pbxproj
index cb54ac99..257870a5 100644
--- a/Hackers.xcodeproj/project.pbxproj
+++ b/Hackers.xcodeproj/project.pbxproj
@@ -1026,13 +1026,15 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 106;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 2KB59GPA9B;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
INFOPLIST_FILE = Extensions/HackersActionExtension/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MARKETING_VERSION = 4.6.4;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.weiranzhang.Hackers.HackersActionExtension;
@@ -1059,13 +1061,15 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 106;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 2KB59GPA9B;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
INFOPLIST_FILE = Extensions/HackersActionExtension/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MARKETING_VERSION = 4.6.4;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.weiranzhang.Hackers.HackersActionExtension;
@@ -1161,7 +1165,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
INFOPLIST_FILE = Extensions/HackersShareExtension/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -1194,7 +1198,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
INFOPLIST_FILE = Extensions/HackersShareExtension/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
@@ -1316,15 +1320,15 @@
CODE_SIGN_ENTITLEMENTS = "App/Supporting Files/Hackers.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 105;
+ CURRENT_PROJECT_VERSION = 106;
DEVELOPMENT_TEAM = 2KB59GPA9B;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "App/Supporting Files/Hackers2-Prefix.pch";
INFOPLIST_FILE = "App/Supporting Files/Hackers-Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- MARKETING_VERSION = 4.6.3;
+ MARKETING_VERSION = 4.6.4;
PRODUCT_BUNDLE_IDENTIFIER = "com.weiranzhang.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = Hackers;
PROVISIONING_PROFILE_SPECIFIER = "Hackers Dev Profile";
@@ -1346,15 +1350,15 @@
CODE_SIGN_ENTITLEMENTS = "App/Supporting Files/Hackers.entitlements";
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 105;
+ CURRENT_PROJECT_VERSION = 106;
DEVELOPMENT_TEAM = 2KB59GPA9B;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "App/Supporting Files/Hackers2-Prefix.pch";
INFOPLIST_FILE = "App/Supporting Files/Hackers-Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- MARKETING_VERSION = 4.6.3;
+ MARKETING_VERSION = 4.6.4;
PRODUCT_BUNDLE_IDENTIFIER = "com.weiranzhang.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = Hackers;
PROVISIONING_PROFILE_SPECIFIER = "Hackers Prod Profile";
diff --git a/Hackers.xcodeproj/xcshareddata/xcschemes/Hackers.xcscheme b/Hackers.xcodeproj/xcshareddata/xcschemes/Hackers.xcscheme
index 8d9e71d7..64d68cc9 100644
--- a/Hackers.xcodeproj/xcshareddata/xcschemes/Hackers.xcscheme
+++ b/Hackers.xcodeproj/xcshareddata/xcschemes/Hackers.xcscheme
@@ -1,6 +1,6 @@
2.6.2' # SwinjectStoryboard needs updating
+ pod 'Swinject'
pod 'SwinjectStoryboard'
pod 'BulletinBoard'
pod 'WhatsNewKit'
diff --git a/Podfile.lock b/Podfile.lock
index 798500d8..515b557b 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -1,15 +1,15 @@
PODS:
- BulletinBoard (5.0.0)
- - DeviceKit (4.4.0)
+ - DeviceKit (4.5.2)
- HNScraper (0.2.2)
- Loaf (0.7.0)
- - Nuke (9.5.0)
+ - Nuke (10.5.2)
- PromiseKit/CorePromise (6.15.3)
- - SwiftLint (0.43.1)
- - SwiftSoup (2.3.2)
- - Swinject (2.6.2)
- - SwinjectStoryboard (2.2.0):
- - Swinject (~> 2.6)
+ - SwiftLint (0.45.1)
+ - SwiftSoup (2.3.3)
+ - Swinject (2.7.1)
+ - SwinjectStoryboard (2.2.2):
+ - Swinject (~> 2.7.1)
- SwipeCellKit (2.7.1)
- WhatsNewKit (1.3.7)
@@ -22,7 +22,7 @@ DEPENDENCIES:
- PromiseKit/CorePromise
- SwiftLint
- SwiftSoup
- - Swinject (~> 2.6.2)
+ - Swinject
- SwinjectStoryboard
- SwipeCellKit
- WhatsNewKit
@@ -53,18 +53,18 @@ CHECKOUT OPTIONS:
SPEC CHECKSUMS:
BulletinBoard: dba77053c2a7b64953f63073f7534165af2edd21
- DeviceKit: 2c5d7485a2fa10b65c0091b2952d30843a6ba06d
+ DeviceKit: c622fc19f795f3e0b4d75d6d11b26604338cdab3
HNScraper: d96632c361238905f2886f83675e75f2153b4dc4
Loaf: d69937cd00649f3fa260beb8b7aef0a1feb861ef
- Nuke: 6f400a4ea957e09149ec335a3c6acdcc814d89e4
+ Nuke: 62d6d401e2b3ce553151a6f5e2f9332878710fbd
PromiseKit: 3b2b6995e51a954c46dbc550ce3da44fbfb563c5
- SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52
- SwiftSoup: f97bc4e988c7729d6457f9642f974c617a6e2510
- Swinject: cf7458774b1b00323080a9c67e47a1ee7f9d2af1
- SwinjectStoryboard: 32512ef16c2b0ff5b8f823b23539c4a50f6d3383
+ SwiftLint: 06ac37e4d38c7068e0935bb30cda95f093bec761
+ SwiftSoup: 8e4844e785a975744f2c2606f8b3844ef67eb259
+ Swinject: ddf78b8486dd9b71a667b852cad919ab4484478e
+ SwinjectStoryboard: 240ce371396da09a4c43c72ee5c148108500e184
SwipeCellKit: 3972254a826da74609926daf59b08d6c72e619ea
WhatsNewKit: c87028c4059dccd113495422801914cc53f6aab0
-PODFILE CHECKSUM: 52b90088cab90c44358c46cd2a92ab6bc5e52db7
+PODFILE CHECKSUM: 01446ada016a8c363277039b82b7b1c2962beffe
-COCOAPODS: 1.10.1
+COCOAPODS: 1.11.2