Upgrade to Xcode 16 (#858)
- Address further restrictions on actor-isolation by using `nonisolated` on: - Combine subjects - Core Data context/controller - Blocks - In previews using inline `@State`, create a custom view instead - Use `@retroactive` in l10n extensions - Fix compile error in WireGuardKit
This commit is contained in:
parent
c5047533b5
commit
008b78cc7c
|
@ -41,7 +41,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
|
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "3a4c78af67dfe181acc657a5539ee3d62d1c9361"
|
"revision" : "3a4c78af67dfe181acc657a5539ee3d62d1c9361",
|
||||||
|
"version" : "0.11.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -58,8 +59,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source-wireguard-go",
|
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source-wireguard-go",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "8d142c806fb7dc4a2cd754d38d99da0d6398b811",
|
"revision" : "256a4a8265b7d214bb35f4e29e18c27e2dc49137",
|
||||||
"version" : "0.9.1"
|
"version" : "0.9.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -76,8 +77,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/passepartoutvpn/wireguard-apple",
|
"location" : "https://github.com/passepartoutvpn/wireguard-apple",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "a896f784bc5ed94f29d97e376be5cfa08d4a5d44",
|
"revision" : "d8bcdf22f1e75d80caac874f302dee86194bb71d",
|
||||||
"version" : "1.1.1"
|
"version" : "1.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -49,13 +49,13 @@ let package = Package(
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.9.0"),
|
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.11.0"),
|
||||||
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "3a4c78af67dfe181acc657a5539ee3d62d1c9361"),
|
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "3a4c78af67dfe181acc657a5539ee3d62d1c9361"),
|
||||||
// .package(path: "../../../passepartoutkit-source"),
|
// .package(path: "../../../passepartoutkit-source"),
|
||||||
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", from: "0.9.1"),
|
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", from: "0.9.1"),
|
||||||
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"),
|
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"),
|
||||||
// .package(path: "../../../passepartoutkit-source-openvpn-openssl"),
|
// .package(path: "../../../passepartoutkit-source-openvpn-openssl"),
|
||||||
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-wireguard-go", from: "0.9.1"),
|
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-wireguard-go", from: "0.9.2"),
|
||||||
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-wireguard-go", revision: "ea39fa396e98cfd2b9a235f0a801aaf03a37e30a"),
|
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-wireguard-go", revision: "ea39fa396e98cfd2b9a235f0a801aaf03a37e30a"),
|
||||||
// .package(path: "../../../passepartoutkit-source-wireguard-go"),
|
// .package(path: "../../../passepartoutkit-source-wireguard-go"),
|
||||||
.package(url: "https://github.com/Cocoanetics/Kvitto", from: "1.0.0")
|
.package(url: "https://github.com/Cocoanetics/Kvitto", from: "1.0.0")
|
||||||
|
|
|
@ -40,15 +40,15 @@ extension AppData {
|
||||||
}
|
}
|
||||||
|
|
||||||
actor CDProviderRepositoryV3: NSObject, ProviderRepository {
|
actor CDProviderRepositoryV3: NSObject, ProviderRepository {
|
||||||
private let context: NSManagedObjectContext
|
private nonisolated let context: NSManagedObjectContext
|
||||||
|
|
||||||
private let backgroundContext: NSManagedObjectContext
|
private nonisolated let backgroundContext: NSManagedObjectContext
|
||||||
|
|
||||||
private let providersSubject: CurrentValueSubject<[ProviderMetadata], Never>
|
private nonisolated let providersSubject: CurrentValueSubject<[ProviderMetadata], Never>
|
||||||
|
|
||||||
private let lastUpdateSubject: CurrentValueSubject<[ProviderID: Date], Never>
|
private nonisolated let lastUpdateSubject: CurrentValueSubject<[ProviderID: Date], Never>
|
||||||
|
|
||||||
private let providersController: NSFetchedResultsController<CDProviderV3>
|
private nonisolated let providersController: NSFetchedResultsController<CDProviderV3>
|
||||||
|
|
||||||
init(context: NSManagedObjectContext, backgroundContext: NSManagedObjectContext) {
|
init(context: NSManagedObjectContext, backgroundContext: NSManagedObjectContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
|
@ -43,17 +43,25 @@ struct NameSection: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
struct ContentView: View {
|
||||||
|
|
||||||
@State
|
@State
|
||||||
var name = ""
|
private var name = ""
|
||||||
|
|
||||||
return Form {
|
var body: some View {
|
||||||
|
Form {
|
||||||
NameSection(
|
NameSection(
|
||||||
name: $name,
|
name: $name,
|
||||||
placeholder: "My name"
|
placeholder: "My name"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.themeForm()
|
.themeForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ContentView()
|
||||||
.withMockEnvironment()
|
.withMockEnvironment()
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,16 +26,16 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import PassepartoutKit
|
import PassepartoutKit
|
||||||
|
|
||||||
public final class ProfileProcessor: ObservableObject {
|
public final class ProfileProcessor: ObservableObject, Sendable {
|
||||||
private let iapManager: IAPManager
|
private let iapManager: IAPManager
|
||||||
|
|
||||||
public let title: (Profile) -> String
|
public nonisolated let title: (Profile) -> String
|
||||||
|
|
||||||
private let _isIncluded: (IAPManager, Profile) -> Bool
|
private nonisolated let _isIncluded: (IAPManager, Profile) -> Bool
|
||||||
|
|
||||||
private let _willSave: (IAPManager, Profile.Builder) throws -> Profile.Builder
|
private nonisolated let _willSave: (IAPManager, Profile.Builder) throws -> Profile.Builder
|
||||||
|
|
||||||
private let _willConnect: (IAPManager, Profile) throws -> Profile
|
private nonisolated let _willConnect: (IAPManager, Profile) throws -> Profile
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
iapManager: IAPManager,
|
iapManager: IAPManager,
|
||||||
|
|
|
@ -31,7 +31,7 @@ import PassepartoutKit
|
||||||
public actor FallbackReceiptReader: AppReceiptReader {
|
public actor FallbackReceiptReader: AppReceiptReader {
|
||||||
private let reader: InAppReceiptReader?
|
private let reader: InAppReceiptReader?
|
||||||
|
|
||||||
private let localReader: (URL) -> InAppReceiptReader?
|
private nonisolated let localReader: (URL) -> InAppReceiptReader?
|
||||||
|
|
||||||
private var pendingTask: Task<InAppReceipt?, Never>?
|
private var pendingTask: Task<InAppReceipt?, Never>?
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ public actor MockAppProductHelper: AppProductHelper {
|
||||||
|
|
||||||
public nonisolated let receiptReader: MockAppReceiptReader
|
public nonisolated let receiptReader: MockAppReceiptReader
|
||||||
|
|
||||||
private let didUpdateSubject: PassthroughSubject<Void, Never>
|
private nonisolated let didUpdateSubject: PassthroughSubject<Void, Never>
|
||||||
|
|
||||||
// set .max to skip entitled products
|
// set .max to skip entitled products
|
||||||
public init(build: Int = .max) {
|
public init(build: Int = .max) {
|
||||||
|
|
|
@ -46,17 +46,17 @@ public actor CoreDataRepository<CD, T>: NSObject,
|
||||||
|
|
||||||
private let entityName: String
|
private let entityName: String
|
||||||
|
|
||||||
private let context: NSManagedObjectContext
|
private nonisolated let context: NSManagedObjectContext
|
||||||
|
|
||||||
private let observingResults: Bool
|
private let observingResults: Bool
|
||||||
|
|
||||||
private let fromMapper: (CD) throws -> T?
|
private nonisolated let fromMapper: (CD) throws -> T?
|
||||||
|
|
||||||
private let toMapper: (T, NSManagedObjectContext) throws -> CD
|
private nonisolated let toMapper: (T, NSManagedObjectContext) throws -> CD
|
||||||
|
|
||||||
private let onResultError: ((Error) -> CoreDataResultAction)?
|
private nonisolated let onResultError: ((Error) -> CoreDataResultAction)?
|
||||||
|
|
||||||
private let entitiesSubject: CurrentValueSubject<EntitiesResult<T>, Never>
|
private nonisolated let entitiesSubject: CurrentValueSubject<EntitiesResult<T>, Never>
|
||||||
|
|
||||||
// cannot easily use CD as generic
|
// cannot easily use CD as generic
|
||||||
private var resultsController: NSFetchedResultsController<CD>
|
private var resultsController: NSFetchedResultsController<CD>
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
//
|
|
||||||
// UUID+RawRepresentable.swift
|
|
||||||
// Passepartout
|
|
||||||
//
|
|
||||||
// Created by Davide De Rosa on 8/11/24.
|
|
||||||
// Copyright (c) 2024 Davide De Rosa. All rights reserved.
|
|
||||||
//
|
|
||||||
// https://github.com/passepartoutvpn
|
|
||||||
//
|
|
||||||
// This file is part of Passepartout.
|
|
||||||
//
|
|
||||||
// Passepartout is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Passepartout is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
extension UUID: RawRepresentable {
|
|
||||||
public var rawValue: String {
|
|
||||||
uuidString
|
|
||||||
}
|
|
||||||
|
|
||||||
public init?(rawValue: RawValue) {
|
|
||||||
self.init(uuidString: rawValue)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -39,7 +39,7 @@ public final class StoreKitHelper<ProductType>: InAppHelper where ProductType: R
|
||||||
|
|
||||||
private var activeTransactions: Set<Transaction>
|
private var activeTransactions: Set<Transaction>
|
||||||
|
|
||||||
private let didUpdateSubject: PassthroughSubject<Void, Never>
|
private nonisolated let didUpdateSubject: PassthroughSubject<Void, Never>
|
||||||
|
|
||||||
private var observer: Task<Void, Never>?
|
private var observer: Task<Void, Never>?
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ extension AppError: LocalizedError {
|
||||||
|
|
||||||
// MARK: - App side
|
// MARK: - App side
|
||||||
|
|
||||||
extension PassepartoutError: LocalizedError {
|
extension PassepartoutError: @retroactive LocalizedError {
|
||||||
public var errorDescription: String? {
|
public var errorDescription: String? {
|
||||||
switch code {
|
switch code {
|
||||||
case .App.ineligibleProfile:
|
case .App.ineligibleProfile:
|
||||||
|
|
|
@ -144,7 +144,7 @@ extension OnDemandModule.Policy: LocalizableEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ProviderID: CustomDebugStringConvertible {
|
extension ProviderID: @retroactive CustomDebugStringConvertible {
|
||||||
public var debugDescription: String {
|
public var debugDescription: String {
|
||||||
rawValue
|
rawValue
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,18 +209,24 @@ private extension OpenVPNCredentialsView {
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
struct ContentView: View {
|
||||||
|
|
||||||
@State
|
@State
|
||||||
var credentials: OpenVPN.Credentials?
|
private var credentials: OpenVPN.Credentials?
|
||||||
|
|
||||||
@State
|
@State
|
||||||
var isInteractive = true
|
private var isInteractive = true
|
||||||
|
|
||||||
return NavigationStack {
|
var body: some View {
|
||||||
|
NavigationStack {
|
||||||
OpenVPNCredentialsView(
|
OpenVPNCredentialsView(
|
||||||
isInteractive: $isInteractive,
|
isInteractive: $isInteractive,
|
||||||
credentials: $credentials
|
credentials: $credentials
|
||||||
)
|
)
|
||||||
.withMockEnvironment()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ContentView()
|
||||||
|
.withMockEnvironment()
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,10 +238,13 @@ private extension EditableListSection {
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
@State
|
struct ContentView: View {
|
||||||
var originalItems = ["One", "Two", "Three"]
|
|
||||||
|
|
||||||
return Form {
|
@State
|
||||||
|
private var originalItems = ["One", "Two", "Three"]
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Form {
|
||||||
EditableListSection(
|
EditableListSection(
|
||||||
"Title",
|
"Title",
|
||||||
addTitle: "Add item",
|
addTitle: "Add item",
|
||||||
|
@ -258,6 +261,10 @@ private extension EditableListSection {
|
||||||
Image(systemName: "arrow.up.arrow.down")
|
Image(systemName: "arrow.up.arrow.down")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ContentView()
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue