Skip to content
This repository was archived by the owner on Sep 20, 2023. It is now read-only.

Commit 7a128a9

Browse files
ismetaninrnystrom
authored andcommitted
Open external links in Safari (#2538)
* Add external links opening in Safari * Fix naming, remove unused IBOutlet * Add missing file * Add canOpenURL check, add assertion call in presentSafari(url:) * Fix defaultKey in Defaults+ExternalLinks * Add assertion call if canOpenURL fails
1 parent 4fb7f73 commit 7a128a9

File tree

5 files changed

+88
-10
lines changed

5 files changed

+88
-10
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// Defaults+ExternalLinks.swift
3+
// Freetime
4+
//
5+
// Created by Ivan Smetanin on 08/12/2018.
6+
// Copyright © 2018 Ryan Nystrom. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
extension UserDefaults {
12+
13+
private static let defaultKey = "com.whoisryannystrom.freetime.should-open-external-links-in-safari"
14+
15+
var shouldOpenExternalLinksInSafari: Bool {
16+
get {
17+
return bool(forKey: UserDefaults.defaultKey)
18+
}
19+
set {
20+
set(newValue, forKey: UserDefaults.defaultKey)
21+
}
22+
}
23+
24+
}

Classes/Settings/Settings.storyboard

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="d42-bu-Upj">
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="d42-bu-Upj">
33
<device id="retina4_7" orientation="portrait">
44
<adaptation id="fullscreen"/>
55
</device>
66
<dependencies>
77
<deployment identifier="iOS"/>
8-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
8+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
99
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
1010
</dependencies>
1111
<scenes>
@@ -14,13 +14,13 @@
1414
<objects>
1515
<tableViewController id="NnB-TU-bkW" customClass="SettingsViewController" customModule="Freetime" customModuleProvider="target" sceneMemberID="viewController">
1616
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="W1i-GH-bg7">
17-
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
17+
<rect key="frame" x="0.0" y="0.0" width="375" height="1000"/>
1818
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
1919
<color key="backgroundColor" red="0.96470588235294119" green="0.97254901960784312" blue="0.98039215686274506" alpha="1" colorSpace="calibratedRGB"/>
2020
<color key="separatorColor" red="0.73725490196078436" green="0.73333333333333328" blue="0.75686274509803919" alpha="1" colorSpace="calibratedRGB"/>
2121
<inset key="separatorInset" minX="16" minY="0.0" maxX="0.0" maxY="0.0"/>
2222
<view key="tableFooterView" contentMode="scaleToFill" id="jkq-3p-p02">
23-
<rect key="frame" x="0.0" y="737.5" width="375" height="44"/>
23+
<rect key="frame" x="0.0" y="781.5" width="375" height="44"/>
2424
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
2525
<subviews>
2626
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version 1.4.0 (1207)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2bb-Lj-p2k" customClass="SettingsLabel" customModule="Freetime" customModuleProvider="target">
@@ -344,9 +344,39 @@
344344
</tableViewCellContentView>
345345
<inset key="separatorInset" minX="16" minY="0.0" maxX="0.0" maxY="0.0"/>
346346
</tableViewCell>
347-
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="Z8j-JQ-qiy" customClass="StyledTableCell" customModule="Freetime" customModuleProvider="target">
347+
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" id="gUI-N4-goV" customClass="StyledTableCell" customModule="Freetime" customModuleProvider="target">
348348
<rect key="frame" x="0.0" y="551.5" width="375" height="44"/>
349349
<autoresizingMask key="autoresizingMask"/>
350+
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="gUI-N4-goV" id="V2v-rp-a9K">
351+
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
352+
<autoresizingMask key="autoresizingMask"/>
353+
<subviews>
354+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Open external links in Safari" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jdo-Qq-YAa" customClass="SettingsLabel" customModule="Freetime" customModuleProvider="target">
355+
<rect key="frame" x="16" y="12" width="201" height="20"/>
356+
<fontDescription key="fontDescription" type="system" pointSize="16"/>
357+
<color key="textColor" red="0.14117647059999999" green="0.16078431369999999" blue="0.18039215689999999" alpha="1" colorSpace="calibratedRGB"/>
358+
<nil key="highlightedColor"/>
359+
</label>
360+
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5on-Qc-M5n">
361+
<rect key="frame" x="311" y="6.5" width="51" height="31"/>
362+
<connections>
363+
<action selector="onOpenExternalLinks:" destination="NnB-TU-bkW" eventType="valueChanged" id="gOq-Th-kLE"/>
364+
<action selector="onSignature:" destination="NnB-TU-bkW" eventType="valueChanged" id="zQD-ww-db9"/>
365+
</connections>
366+
</switch>
367+
</subviews>
368+
<constraints>
369+
<constraint firstItem="jdo-Qq-YAa" firstAttribute="leading" secondItem="V2v-rp-a9K" secondAttribute="leading" constant="16" id="3bG-mE-QDh"/>
370+
<constraint firstItem="5on-Qc-M5n" firstAttribute="centerY" secondItem="V2v-rp-a9K" secondAttribute="centerY" id="6n0-ib-va0"/>
371+
<constraint firstAttribute="trailing" secondItem="5on-Qc-M5n" secondAttribute="trailing" constant="15" id="IIS-7S-wnp"/>
372+
<constraint firstItem="jdo-Qq-YAa" firstAttribute="centerY" secondItem="V2v-rp-a9K" secondAttribute="centerY" id="q65-e6-nBd"/>
373+
</constraints>
374+
</tableViewCellContentView>
375+
<inset key="separatorInset" minX="16" minY="0.0" maxX="0.0" maxY="0.0"/>
376+
</tableViewCell>
377+
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="Z8j-JQ-qiy" customClass="StyledTableCell" customModule="Freetime" customModuleProvider="target">
378+
<rect key="frame" x="0.0" y="595.5" width="375" height="44"/>
379+
<autoresizingMask key="autoresizingMask"/>
350380
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Z8j-JQ-qiy" id="uAb-lB-GZA">
351381
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
352382
<autoresizingMask key="autoresizingMask"/>
@@ -372,7 +402,7 @@
372402
<inset key="separatorInset" minX="16" minY="0.0" maxX="0.0" maxY="0.0"/>
373403
</tableViewCell>
374404
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="McK-NV-R4T" customClass="StyledTableCell" customModule="Freetime" customModuleProvider="target">
375-
<rect key="frame" x="0.0" y="595.5" width="375" height="44"/>
405+
<rect key="frame" x="0.0" y="639.5" width="375" height="44"/>
376406
<autoresizingMask key="autoresizingMask"/>
377407
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="McK-NV-R4T" id="M6U-hF-aEN">
378408
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
@@ -403,14 +433,14 @@
403433
<tableViewSection id="GTg-1u-cvV">
404434
<cells>
405435
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="ku5-ZI-OG9" style="IBUITableViewCellStyleDefault" id="Y2k-Zq-AUW" customClass="StyledTableCell" customModule="Freetime" customModuleProvider="target">
406-
<rect key="frame" x="0.0" y="675.5" width="375" height="44"/>
436+
<rect key="frame" x="0.0" y="719.5" width="375" height="44"/>
407437
<autoresizingMask key="autoresizingMask"/>
408438
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Y2k-Zq-AUW" id="XiT-sq-B22">
409439
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
410440
<autoresizingMask key="autoresizingMask"/>
411441
<subviews>
412442
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Sign Out" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ku5-ZI-OG9" customClass="SettingsLabel" customModule="Freetime" customModuleProvider="target">
413-
<rect key="frame" x="24" y="0.0" width="336" height="43.5"/>
443+
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
414444
<autoresizingMask key="autoresizingMask"/>
415445
<fontDescription key="fontDescription" type="system" pointSize="16"/>
416446
<color key="textColor" red="0.79607843137254897" green="0.14117647058823529" blue="0.19215686274509802" alpha="1" colorSpace="calibratedRGB"/>
@@ -429,6 +459,7 @@
429459
</connections>
430460
</tableView>
431461
<navigationItem key="navigationItem" title="Settings" id="fVs-Zg-aE3"/>
462+
<size key="freeformSize" width="375" height="1000"/>
432463
<connections>
433464
<outlet property="accountsCell" destination="64O-sw-wTx" id="UPX-Wa-mYM"/>
434465
<outlet property="apiStatusLabel" destination="rIC-a2-0GF" id="ceC-Ij-CrY"/>
@@ -439,6 +470,7 @@
439470
<outlet property="defaultReactionLabel" destination="UHH-lU-DUe" id="ew2-Hr-5UH"/>
440471
<outlet property="githubStatusCell" destination="x9n-2O-buf" id="xc3-W3-bZW"/>
441472
<outlet property="markReadSwitch" destination="8dQ-YU-Yuw" id="5jz-5d-osk"/>
473+
<outlet property="openExternalLinksSwitch" destination="5on-Qc-M5n" id="Cvo-TJ-Opl"/>
442474
<outlet property="pushCell" destination="pbF-qp-TdT" id="zVp-UJ-bIl"/>
443475
<outlet property="pushSettingsButton" destination="HFk-Cc-92g" id="1fa-Sc-SQ1"/>
444476
<outlet property="pushSwitch" destination="T30-uT-48L" id="mNm-JM-Q97"/>

Classes/Settings/SettingsViewController.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ GitHubSessionListener {
4646
@IBOutlet weak var pushSwitch: UISwitch!
4747
@IBOutlet weak var pushCell: UITableViewCell!
4848
@IBOutlet weak var pushSettingsButton: UIButton!
49+
@IBOutlet weak var openExternalLinksSwitch: UISwitch!
4950

5051
override func viewDidLoad() {
5152
super.viewDidLoad()
@@ -54,6 +55,7 @@ GitHubSessionListener {
5455
markReadSwitch.isOn = NotificationModelController.readOnOpen
5556
apiStatusView.layer.cornerRadius = 7
5657
signatureSwitch.isOn = Signature.enabled
58+
openExternalLinksSwitch.isOn = UserDefaults.standard.shouldOpenExternalLinksInSafari
5759
pushSettingsButton.accessibilityLabel = NSLocalizedString("How we send push notifications in GitHawk", comment: "")
5860

5961
updateBadge()
@@ -286,6 +288,10 @@ GitHubSessionListener {
286288
showContextualMenu(PushNotificationsDisclaimerViewController())
287289
}
288290

291+
@IBAction private func onOpenExternalLinks(_ sender: Any) {
292+
UserDefaults.standard.shouldOpenExternalLinksInSafari = openExternalLinksSwitch.isOn
293+
}
294+
289295
// MARK: NewIssueTableViewControllerDelegate
290296

291297
func didDismissAfterCreatingIssue(model: IssueDetailsModel) {

Classes/View Controllers/UIViewController+Safari.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,20 @@ import SafariServices
1212
extension UIViewController {
1313

1414
func presentSafari(url: URL) {
15-
guard let safariViewController = try? SFSafariViewController.configured(with: url) else { return }
16-
route_present(to: safariViewController)
15+
if UserDefaults.standard.shouldOpenExternalLinksInSafari {
16+
guard UIApplication.shared.canOpenURL(url) else {
17+
assertionFailure("Can't open url: \(url)")
18+
return
19+
}
20+
UIApplication.shared.open(url)
21+
} else {
22+
do {
23+
let safariViewController = try SFSafariViewController.configured(with: url)
24+
route_present(to: safariViewController)
25+
} catch {
26+
assertionFailure(error.localizedDescription)
27+
}
28+
}
1729
}
1830

1931
func presentProfile(login: String) {

Freetime.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@
474474
7BBFEE5B1F8A8A0400C68E47 /* SearchBarSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBFEE581F8A8A0400C68E47 /* SearchBarSectionController.swift */; };
475475
7BF2239D1F91056C006CC9A2 /* File+Filename.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BF2239C1F91056C006CC9A2 /* File+Filename.swift */; };
476476
8960A556E8729CB4031DD641 /* Pods_FreetimeTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 516CF27F9258BBD3E034F09D /* Pods_FreetimeTests.framework */; };
477+
8B56452C21BC0DFF003199E2 /* Defaults+ExternalLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B56452B21BC0DFF003199E2 /* Defaults+ExternalLinks.swift */; };
477478
8B75B03A211F044E009EFAEC /* UIContentSizeCategoryChangeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B75B039211F044E009EFAEC /* UIContentSizeCategoryChangeHandler.swift */; };
478479
98003D8D1FCAD7FC00755C17 /* LabelDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98003D8C1FCAD7FC00755C17 /* LabelDetails.swift */; };
479480
98647DF31F758CCF00A4DE7A /* NewIssueTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98647DF21F758CCF00A4DE7A /* NewIssueTableViewController.swift */; };
@@ -1072,6 +1073,7 @@
10721073
7BBFEE561F8A8A0400C68E47 /* SearchBarCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBarCell.swift; sourceTree = "<group>"; };
10731074
7BBFEE581F8A8A0400C68E47 /* SearchBarSectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBarSectionController.swift; sourceTree = "<group>"; };
10741075
7BF2239C1F91056C006CC9A2 /* File+Filename.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "File+Filename.swift"; sourceTree = "<group>"; };
1076+
8B56452B21BC0DFF003199E2 /* Defaults+ExternalLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Defaults+ExternalLinks.swift"; sourceTree = "<group>"; };
10751077
8B75B039211F044E009EFAEC /* UIContentSizeCategoryChangeHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIContentSizeCategoryChangeHandler.swift; sourceTree = "<group>"; };
10761078
98003D8C1FCAD7FC00755C17 /* LabelDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelDetails.swift; sourceTree = "<group>"; };
10771079
98647DF21F758CCF00A4DE7A /* NewIssueTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewIssueTableViewController.swift; sourceTree = "<group>"; };
@@ -2051,6 +2053,7 @@
20512053
297FB7771F51128A00F2E618 /* SettingsAccountsViewController.swift */,
20522054
29764C131FDC4DB60095FF95 /* SettingsLabel.swift */,
20532055
292FF8AD1F2FD4A8009E63F7 /* SettingsViewController.swift */,
2056+
8B56452B21BC0DFF003199E2 /* Defaults+ExternalLinks.swift */,
20542057
);
20552058
path = Settings;
20562059
sourceTree = "<group>";
@@ -2959,6 +2962,7 @@
29592962
299E86491EFD9DBB00E5FE70 /* FlexController.m in Sources */,
29602963
29F3A18620CBF99E00645CB7 /* NotificationModelController.swift in Sources */,
29612964
29C167741ECA0DBB00439D62 /* GithubAPIDateFormatter.swift in Sources */,
2965+
8B56452C21BC0DFF003199E2 /* Defaults+ExternalLinks.swift in Sources */,
29622966
290CA770216AE91300DE04F8 /* UITabBarController+SelectType.swift in Sources */,
29632967
294434E11FB1F2DA00050C06 /* BookmarkNavigationController.swift in Sources */,
29642968
29BCA7FE212137E100753A3C /* IssueTargetBranchModel.swift in Sources */,

0 commit comments

Comments
 (0)