Skip to content

Commit

Permalink
Add initial AppKitExtensions local package (#3082)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1201037661562251/1207999635472099/f
Tech Design URL:
CC:

**Description**:
As title.
The most immediate purpose is so it can be used in DBP. It also seems we
were doing some crimes to include the NSApplication extension in the net
p targets, so this PR also unwinds that.
I've made notes inline where I think specific scrutiny is warranted.

**Steps to test this PR**:
1. Smoke test the app and specifically the VPN to ensure nothing breaks

<!--
Tagging instructions
If this PR isn't ready to be merged for whatever reason it should be
marked with the `DO NOT MERGE` label (particularly if it's a draft)
If it's pending Product Review/PFR, please add the `Pending Product
Review` label.

If at any point it isn't actively being worked on/ready for
review/otherwise moving forward (besides the above PR/PFR exception)
strongly consider closing it (or not opening it in the first place). If
you decide not to close it, make sure it's labelled to make it clear the
PRs state and comment with more information.
-->

**Definition of Done**:

* [ ] Does this PR satisfy our [Definition of
Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)?

---
###### Internal references:
[Pull Request Review
Checklist](https://app.asana.com/0/1202500774821704/1203764234894239/f)
[Software Engineering
Expectations](https://app.asana.com/0/59792373528535/199064865822552)
[Technical Design
Template](https://app.asana.com/0/59792373528535/184709971311943)
[Pull Request
Documentation](https://app.asana.com/0/1202500774821704/1204012835277482/f)

---------

Co-authored-by: Dominik Kapusta <[email protected]>
  • Loading branch information
THISISDINOSAUR and ayoy authored Aug 12, 2024
1 parent 0fcccdc commit 9d36949
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 114 deletions.
73 changes: 65 additions & 8 deletions DuckDuckGo.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

92 changes: 0 additions & 92 deletions DuckDuckGo/Common/Extensions/NSApplicationExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,103 +21,11 @@ import Combine

extension NSApplication {

var isSandboxed: Bool {
ProcessInfo.processInfo.environment["APP_SANDBOX_CONTAINER_ID"] != nil
}

enum RunType {
case normal
case unitTests
case integrationTests
case uiTests
case uiTestsOnboarding
case xcPreviews

/// Defines if app run type requires loading full environment, i.e. databases, saved state, keychain etc.
var requiresEnvironment: Bool {
switch self {
case .normal, .integrationTests, .uiTests, .uiTestsOnboarding:
return true
case .unitTests, .xcPreviews:
return false
}
}
}

static let runType: RunType = {
#if DEBUG
if let testBundlePath = ProcessInfo().environment["XCTestBundlePath"] {
if testBundlePath.contains("Unit") {
return .unitTests
} else if testBundlePath.contains("Integration") {
return .integrationTests
} else {
return .uiTests
}
} else if ProcessInfo().environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
return .xcPreviews
} else if ProcessInfo.processInfo.environment["UITEST_MODE_ONBOARDING"] == "1"{
return .uiTestsOnboarding
} else if ProcessInfo.processInfo.environment["UITEST_MODE"] == "1" {
return .uiTests
} else {
return .normal
}
#elseif REVIEW
let isCI = ProcessInfo.processInfo.environment["CI"] != nil
// UITEST_MODE is set from UI Tests code, but this check didn't work reliably
// in CI on its own, so we're defaulting all CI runs of the REVIEW app to UI Tests
if ProcessInfo().environment["UITEST_MODE_ONBOARDING"] == "1" {
return .uiTestsOnboarding
}
if ProcessInfo.processInfo.environment["UITEST_MODE"] == "1" || isCI {
return .uiTests
}
return .normal
#else
return .normal
#endif
}()
var runType: RunType { Self.runType }

#if !NETWORK_EXTENSION && !SANDBOX_TEST_TOOL
var mainMenuTyped: MainMenu {
return mainMenu as! MainMenu // swiftlint:disable:this force_cast
}

var delegateTyped: AppDelegate {
return delegate as! AppDelegate // swiftlint:disable:this force_cast
}
#endif

var isCommandPressed: Bool {
currentEvent?.modifierFlags.contains(.command) ?? false
}

var isShiftPressed: Bool {
currentEvent?.modifierFlags.contains(.shift) ?? false
}

var isOptionPressed: Bool {
currentEvent?.modifierFlags.contains(.option) ?? false
}

var isReturnOrEnterPressed: Bool {
guard let event = currentEvent,
case .keyDown = event.type
else { return false }
return event.keyCode == 36 || event.keyCode == 76
}

func isActivePublisher() -> AnyPublisher<Bool, Never> {
let activated = NotificationCenter.default
.publisher(for: NSApplication.didBecomeActiveNotification).map { _ in true }
let deactivated = NotificationCenter.default
.publisher(for: NSApplication.didResignActiveNotification).map { _ in false }

return Just(self.isActive)
.merge(with: activated.merge(with: deactivated))
.eraseToAnyPublisher()
}

}
1 change: 1 addition & 0 deletions DuckDuckGo/Common/Extensions/URLExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import AppKit
import BrowserServicesKit
import Common
import Foundation
import AppKitExtensions

extension URL.NavigationalScheme {

Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import AppKit
import Foundation
import AppKitExtensions

extension UserDefaults {
/// The app group's shared UserDefaults
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/FileDownload/Services/DownloadListStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import CoreData
import Foundation
import UniformTypeIdentifiers
import PixelKit
import AppKitExtensions

protocol DownloadListStoring {

Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/RemoteMessaging/RemoteMessagingDebugMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import AppKit
import RemoteMessaging
import AppKitExtensions

final class RemoteMessagingDebugMenu: NSMenu {

Expand Down
14 changes: 0 additions & 14 deletions DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -440,17 +440,3 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate {
}
}
}

extension NSApplication {

enum RunType: Int, CustomStringConvertible {
case normal
var description: String {
switch self {
case .normal: return "normal"
}
}
}
static var runType: RunType { .normal }

}
9 changes: 9 additions & 0 deletions LocalPackages/AppKitExtensions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
24 changes: 24 additions & 0 deletions LocalPackages/AppKitExtensions/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "AppKitExtensions",
platforms: [ .macOS("11.4") ],
products: [
.library(name: "AppKitExtensions", targets: ["AppKitExtensions"]),
],
dependencies: [
],
targets: [
.target(
name: "AppKitExtensions",
dependencies: [
],
swiftSettings: [
.define("DEBUG", .when(configuration: .debug))
]
),
]
)
6 changes: 6 additions & 0 deletions LocalPackages/AppKitExtensions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# AppKitExtensions

A package for any extensions on AppKit classes, so local packages and other targets besides the main app can use them.

- If you need to add a new one put it here unless it's specific to the main app.
- If you need to modify on existing one, consider moving it here.
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// NSApplicationExtension.swift
//
// Copyright © 2020 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Cocoa
import Combine

public extension NSApplication {

var isSandboxed: Bool {
ProcessInfo.processInfo.environment["APP_SANDBOX_CONTAINER_ID"] != nil
}

enum RunType {
case normal
case unitTests
case integrationTests
case uiTests
case uiTestsOnboarding
case xcPreviews

/// Defines if app run type requires loading full environment, i.e. databases, saved state, keychain etc.
public var requiresEnvironment: Bool {
switch self {
case .normal, .integrationTests, .uiTests, .uiTestsOnboarding:
return true
case .unitTests, .xcPreviews:
return false
}
}
}

static let runType: RunType = {
let isCI = ProcessInfo.processInfo.environment["CI"] != nil

if let testBundlePath = ProcessInfo().environment["XCTestBundlePath"] {
if testBundlePath.contains("Unit") {
return .unitTests
} else if testBundlePath.contains("Integration") {
return .integrationTests
} else {
return .uiTests
}
} else if ProcessInfo().environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
return .xcPreviews
} else if ProcessInfo.processInfo.environment["UITEST_MODE_ONBOARDING"] == "1"{
return .uiTestsOnboarding
} else if ProcessInfo.processInfo.environment["UITEST_MODE"] == "1" || isCI {
return .uiTests
} else {
return .normal
}
}()
var runType: RunType { Self.runType }

var isCommandPressed: Bool {
currentEvent?.modifierFlags.contains(.command) ?? false
}

var isShiftPressed: Bool {
currentEvent?.modifierFlags.contains(.shift) ?? false
}

var isOptionPressed: Bool {
currentEvent?.modifierFlags.contains(.option) ?? false
}

var isReturnOrEnterPressed: Bool {
guard let event = currentEvent,
case .keyDown = event.type
else { return false }
return event.keyCode == 36 || event.keyCode == 76
}

func isActivePublisher() -> AnyPublisher<Bool, Never> {
let activated = NotificationCenter.default
.publisher(for: NSApplication.didBecomeActiveNotification).map { _ in true }
let deactivated = NotificationCenter.default
.publisher(for: NSApplication.didResignActiveNotification).map { _ in false }

return Just(self.isActive)
.merge(with: activated.merge(with: deactivated))
.eraseToAnyPublisher()
}

}

0 comments on commit 9d36949

Please sign in to comment.