Skip to content

Commit

Permalink
increase deployment target to iOS 14
Browse files Browse the repository at this point in the history
this PR increases the deployment target to iOS 14, meaning that iOS 13 is no longer supported.

the reason is that the "modern" menus are supported since iOS 14 only, and using them has quote some postive effect in UI.

in theory one could provide fallbacks,
as in #2522 , however, that is comparable much effort as we have to duplicate the logic or add an abstraction layer.

that seems not to be worth the effort:

i checked some stats, this change will affect 0.16% of users - but most of them should even be able to update their devices (all devices that got iOS 13 also got iOS 15)
(so, we could also discontinue supporting iOS 14 at some point, but that has 4x more users, so, let's give them a little more time, until we really have bigger incentive)

cmp. #2459
  • Loading branch information
r10s committed Jan 22, 2025
1 parent a4b7542 commit 2eca435
Show file tree
Hide file tree
Showing 10 changed files with 36 additions and 143 deletions.
4 changes: 2 additions & 2 deletions DcCore/DcCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -442,7 +442,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
Expand Down
30 changes: 5 additions & 25 deletions DcCore/DcCore/DC/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,25 @@ public class DcLogger {
let osLog: AnyObject?

public init() {
if #available(iOS 14.0, *) {
osLog = Logger(subsystem: DcLogger.subsystem, category: DcLogger.category) as AnyObject
} else {
osLog = nil
}
osLog = Logger(subsystem: DcLogger.subsystem, category: DcLogger.category) as AnyObject
}

public func error(_ message: String) {
if #available(iOS 14.0, *) {
(osLog as? Logger)?.error("❤️ \(message, privacy: .public)") // "public" is needed to show lines; core takes care of privacy
} else {
os_log("❤️ %{public}s", log: .default, type: .error, message)
}
(osLog as? Logger)?.error("❤️ \(message, privacy: .public)") // "public" is needed to show lines; core takes care of privacy
}

public func warning(_ message: String) {
if #available(iOS 14.0, *) {
(osLog as? Logger)?.warning("🧡 \(message, privacy: .public)")
} else {
os_log("🧡 %{public}s", log: .default, type: .default /* there is no .warning */, message)
}
(osLog as? Logger)?.warning("🧡 \(message, privacy: .public)")
}

public func info(_ message: String) {
if #available(iOS 14.0, *) {
(osLog as? Logger)?.notice("💙 \(message, privacy: .public)") // info() is not persisted
} else {
os_log("💙 %{public}s", log: .default, type: .default /* .default equals notice() and is persisted */, message)
}
(osLog as? Logger)?.notice("💙 \(message, privacy: .public)") // info() is not persisted
}

// debug() marked as DEBUG as these lines are for, well debugging. and should not being released. otherwise, use info()
#if DEBUG
public func debug(_ message: String) {
if #available(iOS 14.0, *) {
(osLog as? Logger)?.debug("💚 \(message, privacy: .public)")
} else {
os_log("💚 %{public}s", log: .default, type: .debug, message)
}
(osLog as? Logger)?.debug("💚 \(message, privacy: .public)")
}
#endif
}
16 changes: 8 additions & 8 deletions deltachat-ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2042,7 +2042,7 @@
"\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImageWebPCoder\"",
);
INFOPLIST_FILE = DcShare/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -2086,7 +2086,7 @@
"\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImageWebPCoder\"",
);
INFOPLIST_FILE = DcShare/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -2167,7 +2167,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.50.5;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -2226,7 +2226,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.50.5;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -2255,7 +2255,7 @@
/usr/local/include,
);
INFOPLIST_FILE = "deltachat-ios/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -2324,7 +2324,7 @@
/usr/local/include,
);
INFOPLIST_FILE = "deltachat-ios/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -2390,7 +2390,7 @@
INFOPLIST_FILE = DcNotificationService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = DcNotificationService;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 merlinux GmbH. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -2425,7 +2425,7 @@
INFOPLIST_FILE = DcNotificationService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = DcNotificationService;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 merlinux GmbH. All rights reserved.";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
60 changes: 2 additions & 58 deletions deltachat-ios/Chat/ChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1168,16 +1168,12 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate {
$0.setSize(CGSize(width: 40, height: 40), animated: false)
$0.accessibilityLabel = String.localized("menu_add_attachment")
$0.accessibilityTraits = .button
if #available(iOS 14.0, *) {
$0.showsMenuAsPrimaryAction = true
$0.menu = clipperButtonMenu()
}
$0.showsMenuAsPrimaryAction = true
$0.menu = clipperButtonMenu()
}.onSelected {
$0.tintColor = UIColor.themeColor(light: .lightGray, dark: .darkGray)
}.onDeselected {
$0.tintColor = DcColors.primary
}.onTouchUpInside { [weak self] _ in
self?.clipperButtonPressed()
}
]

Expand Down Expand Up @@ -1206,7 +1202,6 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate {
}
}

@available(iOS 14, *)
private func clipperButtonMenu() -> UIMenu {
func action(localized: String, systemImage: String, attributes: UIMenuElement.Attributes = [], handler: @escaping () -> Void) -> UIAction {
UIAction(title: String.localized(localized), image: UIImage(systemName: systemImage), attributes: attributes, handler: { _ in handler() })
Expand Down Expand Up @@ -1238,57 +1233,6 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate {
return UIMenu(children: actions)
}

/// On iOS 13 we still use the action sheet but iOS 14+ has a UIMenu
@objc private func clipperButtonPressed() {
guard #unavailable(iOS 14) else { return }
func action(localized: String, style: UIAlertAction.Style = .default, handler: @escaping () -> Void) -> UIAlertAction {
UIAlertAction(title: String.localized(localized), style: style, handler: { _ in handler() })
}
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .safeActionSheet)
let galleryAction = action(localized: "gallery", handler: showPhotoVideoLibrary)
let cameraAction = action(localized: "camera", handler: showCameraViewController)
let documentAction = action(localized: "files", handler: showDocumentLibrary)
let voiceMessageAction = action(localized: "voice_message", handler: showVoiceMessageRecorder)
let sendContactAction = action(localized: "contact", handler: showContactList)
let appPickerAction = action(localized: "webxdc_apps", handler: showAppPicker)

let isLocationStreaming = dcContext.isSendingLocationsToChat(chatId: chatId)
let locationStreamingAction = action(
localized: isLocationStreaming ? "stop_sharing_location" : "location",
style: isLocationStreaming ? .destructive : .default,
handler: locationStreamingButtonPressed
)

alert.addAction(cameraAction)
alert.addAction(galleryAction)
alert.addAction(appPickerAction)
alert.addAction(documentAction)
alert.addAction(voiceMessageAction)

if let config = dcContext.getConfig("webrtc_instance"), !config.isEmpty {
let videoChatInvitation = action(localized: "videochat", handler: videoChatButtonPressed)
alert.addAction(videoChatInvitation)
}

if UserDefaults.standard.bool(forKey: "location_streaming") {
alert.addAction(locationStreamingAction)
}

alert.addAction(sendContactAction)

alert.addAction(UIAlertAction(title: String.localized("cancel"), style: .cancel, handler: nil))

self.present(alert, animated: true, completion: {
// unfortunately, voiceMessageAction.accessibilityHint does not work,
// but this hack does the trick
if UIAccessibility.isVoiceOverRunning {
if let view = voiceMessageAction.value(forKey: "__representer") as? UIView {
view.accessibilityHint = String.localized("a11y_voice_message_hint_ios")
}
}
})
}

private func confirmationAlert(title: String, actionTitle: String, actionStyle: UIAlertAction.Style = .default, actionHandler: @escaping ((UIAlertAction) -> Void), cancelHandler: ((UIAlertAction) -> Void)? = nil) {
let alert = UIAlertController(title: title,
message: nil,
Expand Down
11 changes: 4 additions & 7 deletions deltachat-ios/Controller/WebViewViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,10 @@ class WebViewViewController: UIViewController, WKNavigationDelegate {
var dcContext: DcContext

open var configuration: WKWebViewConfiguration {
let preferences = WKPreferences()
let config = WKWebViewConfiguration()
if #available(iOS 14.0, *) {
config.defaultWebpagePreferences.allowsContentJavaScript = false
} else {
preferences.javaScriptEnabled = false
}
let preferences = WKPreferences()

config.defaultWebpagePreferences.allowsContentJavaScript = false
config.preferences = preferences
return config
}
Expand Down Expand Up @@ -115,7 +112,7 @@ class WebViewViewController: UIViewController, WKNavigationDelegate {
webView.scrollView.keyboardDismissMode = .interactive
webView.scrollView.contentInset.bottom = 0

if allowSearch, #available(iOS 14.0, *) {
if allowSearch {
navigationItem.searchController = searchController
}
accessoryViewContainer.setLeftStackViewWidthConstant(to: 0, animated: false)
Expand Down
7 changes: 2 additions & 5 deletions deltachat-ios/Controller/WebxdcViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,8 @@ class WebxdcViewController: WebViewViewController {
config.allowsInlineMediaPlayback = true
preferences.isFraudulentWebsiteWarningEnabled = true

if #available(iOS 14.0, *) {
config.defaultWebpagePreferences.allowsContentJavaScript = true
} else {
preferences.javaScriptEnabled = true
}
config.defaultWebpagePreferences.allowsContentJavaScript = true

preferences.javaScriptCanOpenWindowsAutomatically = false
config.preferences = preferences
return config
Expand Down
6 changes: 2 additions & 4 deletions deltachat-ios/Extensions/UIPasteboard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import UIKit
import UniformTypeIdentifiers

extension UIPasteboard {
/// Also returns true for webp (on iOS 14+)
/// Also returns true for webp
public var hasImagesExtended: Bool {
guard #available(iOS 14.0, *) else { return hasImages }
return hasImages || types.contains(UTType.webP.identifier)
}

/// Also returns webp image (on iOS 14+)
/// Also returns webp image
public var imageExtended: UIImage? {
guard #available(iOS 14.0, *) else { return image }
return image ?? UIImage.sd_image(withWebPData: data(forPasteboardType: UTType.webP.identifier))
}
}
23 changes: 7 additions & 16 deletions deltachat-ios/Helper/ChatDropInteraction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,13 @@ public class ChatDropInteraction {
public weak var delegate: ChatDropInteractionDelegate?

public func dropInteraction(canHandle session: UIDropSession) -> Bool {
if #available(iOS 14.0, *) {
return session.items.count == 1 && session.hasItemsConforming(toTypeIdentifiers: [
UTType.image.identifier,
UTType.video.identifier,
UTType.movie.identifier,
UTType.text.identifier,
UTType.url.identifier,
UTType.item.identifier])
}
return session.items.count == 1 && session.hasItemsConforming(toTypeIdentifiers: [
kUTTypeImage as String,
kUTTypeText as String,
kUTTypeMovie as String,
kUTTypeVideo as String,
kUTTypeURL as String,
kUTTypeItem as String])
return session.items.count == 1 && session.hasItemsConforming(toTypeIdentifiers: [
UTType.image.identifier,
UTType.video.identifier,
UTType.movie.identifier,
UTType.text.identifier,
UTType.url.identifier,
UTType.item.identifier])
}

public func dropInteraction(sessionDidUpdate session: UIDropSession) -> UIDropProposal {
Expand Down
7 changes: 1 addition & 6 deletions deltachat-ios/Helper/LocationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,7 @@ class LocationManager: NSObject, CLLocationManagerDelegate {

func shareLocation(chatId: Int, duration: Int) -> Bool {
if duration > 0 {
var authStatus: CLAuthorizationStatus
if #available(iOS 14.0, *) {
authStatus = locationManager.authorizationStatus
} else {
authStatus = CLLocationManager.authorizationStatus()
}
let authStatus = locationManager.authorizationStatus
switch authStatus {
case .notDetermined:
// keep chatId and duration for user's authorization decision
Expand Down
15 changes: 3 additions & 12 deletions deltachat-ios/Helper/MediaPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,10 @@ class MediaPicker: NSObject, UINavigationControllerDelegate {
func showDocumentLibrary(selectFolder: Bool = false) {
let documentPicker: UIDocumentPickerViewController
if selectFolder {
if #available(iOS 15.0, *) {
documentPicker = .init(forOpeningContentTypes: [UTType.archive], asCopy: false)
} else {
documentPicker = .init(documentTypes: [kUTTypeArchive] as [String], in: .open)
}
documentPicker = .init(forOpeningContentTypes: [UTType.archive], asCopy: false)
} else {
if #available(iOS 15.0, *) {
let types = [UTType.pdf, .text, .rtf, .spreadsheet, .vCard, .zip, .image, .data]
documentPicker = .init(forOpeningContentTypes: types, asCopy: true)
} else {
let types = [kUTTypePDF, kUTTypeText, kUTTypeRTF, kUTTypeSpreadsheet, kUTTypeVCard, kUTTypeZipArchive, kUTTypeImage, kUTTypeData]
documentPicker = .init(documentTypes: types as [String], in: .import)
}
let types = [UTType.pdf, .text, .rtf, .spreadsheet, .vCard, .zip, .image, .data]
documentPicker = .init(forOpeningContentTypes: types, asCopy: true)
}
documentPicker.delegate = self
documentPicker.allowsMultipleSelection = false
Expand Down

0 comments on commit 2eca435

Please sign in to comment.