Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SwiftUI improvements #149

Merged
merged 10 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ on:
jobs:
carthage:
name: Carthage
runs-on: macos-13
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: AckeeCZ/load-xcode-version@1.1.0
- uses: AckeeCZ/load-xcode-version@v1
- name: Build
run: carthage build --no-skip-current --cache-builds --use-xcframeworks
- uses: actions/cache@v3
Expand All @@ -23,10 +23,10 @@ jobs:
${{ runner.os }}-carthage-
spm:
name: SPM
runs-on: macos-13
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: AckeeCZ/load-xcode-version@1.1.0
- uses: AckeeCZ/load-xcode-version@v1
- name: Build
run: swift build -c release
- uses: actions/cache@v3
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/docbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ jobs:
# Must be set to this for deploying to GitHub Pages
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: macos-13
runs-on: macos-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v4
- name: Check Xcode version ✅
uses: AckeeCZ/load-xcode-version@1.1.0
uses: AckeeCZ/load-xcode-version@v1
- name: Build DocC
run: |
xcodebuild docbuild -scheme ACKategories \
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ on: [workflow_call]
jobs:
xcodebuild:
name: Xcodebuild
runs-on: macos-13
runs-on: macos-latest
env:
IOS_DEVICE: iPhone 15 Pro Max
steps:
- uses: actions/checkout@v4
- uses: AckeeCZ/load-xcode-version@1.1.0
- uses: AckeeCZ/load-xcode-version@v1
- name: iOS tests
run: set -o pipefail && xcodebuild test -scheme ACKategories -resultBundlePath Tests-iOS.xcresult -sdk iphonesimulator -destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=latest" ONLY_ACTIVE_ARCH=YES | xcpretty
- uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -48,10 +48,10 @@ jobs:
path: Tests-tvOS.xcresult
spm:
name: SPM
runs-on: macos-13
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: AckeeCZ/load-xcode-version@1.1.0
- uses: AckeeCZ/load-xcode-version@v1
- name: SPM build
run: swift build
- name: SPM tests
Expand Down
2 changes: 1 addition & 1 deletion .github/xcode-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
15.2
15.4
8 changes: 8 additions & 0 deletions ACKategories.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
6922C77D2AFD1C1A00519CDF /* UINavigationControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6922C77C2AFD1C1A00519CDF /* UINavigationControllerTests.swift */; };
6922C7802AFD1C8B00519CDF /* Dummies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E0A6A02AFD114600C8E8D9 /* Dummies.swift */; };
6922C7812AFD1C8B00519CDF /* FlowCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E0A6A12AFD114600C8E8D9 /* FlowCoordinatorTests.swift */; };
69246CFB2BDFE77400AB31A1 /* SwiftUIColorsTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69246CFA2BDFE77400AB31A1 /* SwiftUIColorsTheme.swift */; };
693A92652B3DB290008B3DC3 /* Networking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 693A925D2B3DB290008B3DC3 /* Networking.framework */; };
693A927B2B3DB2AA008B3DC3 /* RequestAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693A92732B3DB2AA008B3DC3 /* RequestAddress.swift */; };
693A927C2B3DB2AA008B3DC3 /* APIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693A92742B3DB2AA008B3DC3 /* APIService.swift */; };
Expand All @@ -33,6 +34,7 @@
693A92A42B3DB394008B3DC3 /* HTTPResponse+TestData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693A929E2B3DB394008B3DC3 /* HTTPResponse+TestData.swift */; };
693A92A52B3DB394008B3DC3 /* URL+TestData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693A929F2B3DB394008B3DC3 /* URL+TestData.swift */; };
693A92A62B3DB39F008B3DC3 /* ACKategoriesTesting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 693A92912B3DB388008B3DC3 /* ACKategoriesTesting.framework */; };
693B39B72BF2359B00DF7C5E /* ACKHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693B39B62BF2359B00DF7C5E /* ACKHostingController.swift */; };
694D14EB2B3DD61A0083E614 /* VersionUpdateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 694D14E92B3DD6190083E614 /* VersionUpdateManager.swift */; };
694D14EC2B3DD61A0083E614 /* MinBuildNumberFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 694D14EA2B3DD6190083E614 /* MinBuildNumberFetcher.swift */; };
694D14EE2B3DD64C0083E614 /* VersionUpdateFetcher_Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 694D14ED2B3DD64C0083E614 /* VersionUpdateFetcher_Mock.swift */; };
Expand Down Expand Up @@ -223,6 +225,7 @@
6922C77C2AFD1C1A00519CDF /* UINavigationControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UINavigationControllerTests.swift; sourceTree = "<group>"; };
6922C77E2AFD1C3300519CDF /* ACKategoriesResponder.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = ACKategoriesResponder.xctestplan; sourceTree = "<group>"; };
6922C77F2AFD1C5000519CDF /* ACKategories.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = ACKategories.xctestplan; sourceTree = "<group>"; };
69246CFA2BDFE77400AB31A1 /* SwiftUIColorsTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUIColorsTheme.swift; sourceTree = "<group>"; };
693A925D2B3DB290008B3DC3 /* Networking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Networking.framework; sourceTree = BUILT_PRODUCTS_DIR; };
693A92642B3DB290008B3DC3 /* NetworkingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetworkingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
693A92732B3DB2AA008B3DC3 /* RequestAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestAddress.swift; sourceTree = "<group>"; };
Expand All @@ -244,6 +247,7 @@
693A929D2B3DB394008B3DC3 /* HTTPURLResponse+TestData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HTTPURLResponse+TestData.swift"; sourceTree = "<group>"; };
693A929E2B3DB394008B3DC3 /* HTTPResponse+TestData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HTTPResponse+TestData.swift"; sourceTree = "<group>"; };
693A929F2B3DB394008B3DC3 /* URL+TestData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URL+TestData.swift"; sourceTree = "<group>"; };
693B39B62BF2359B00DF7C5E /* ACKHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACKHostingController.swift; sourceTree = "<group>"; };
694D14E92B3DD6190083E614 /* VersionUpdateManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionUpdateManager.swift; sourceTree = "<group>"; };
694D14EA2B3DD6190083E614 /* MinBuildNumberFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinBuildNumberFetcher.swift; sourceTree = "<group>"; };
694D14ED2B3DD64C0083E614 /* VersionUpdateFetcher_Mock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionUpdateFetcher_Mock.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -647,7 +651,9 @@
69E0A6032AFD10BE00C8E8D9 /* SwiftUIExtensions */ = {
isa = PBXGroup;
children = (
69246CFA2BDFE77400AB31A1 /* SwiftUIColorsTheme.swift */,
69E0A6042AFD10BE00C8E8D9 /* FontModifier.swift */,
693B39B62BF2359B00DF7C5E /* ACKHostingController.swift */,
);
path = SwiftUIExtensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -1264,6 +1270,7 @@
69ACD6DE2AFD133A0021127B /* DateExtensions.swift in Sources */,
69ACD6DF2AFD133A0021127B /* DateFormatting.swift in Sources */,
69ACD6E02AFD133A0021127B /* DictionaryExtensions.swift in Sources */,
69246CFB2BDFE77400AB31A1 /* SwiftUIColorsTheme.swift in Sources */,
69ACD6E12AFD133A0021127B /* ErrorHandlers.swift in Sources */,
69ACD6E32AFD133A0021127B /* IntExtensions.swift in Sources */,
69ACD6E42AFD133A0021127B /* NSAttributedStringExtensions.swift in Sources */,
Expand All @@ -1290,6 +1297,7 @@
69ACD6F62AFD133A0021127B /* UISearchBarExtensions.swift in Sources */,
69ACD6F72AFD133A0021127B /* UIStackViewExtensions.swift in Sources */,
69ACD6F82AFD133A0021127B /* UIView+Spacer.swift in Sources */,
693B39B72BF2359B00DF7C5E /* ACKHostingController.swift in Sources */,
69ACD6F92AFD133A0021127B /* UIViewController+Children.swift in Sources */,
6A72B2222B1A15AC00A59EDD /* BackGesture.swift in Sources */,
69ACD6FA2AFD133A0021127B /* UIViewController+FrontMost.swift in Sources */,
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

## Next

- SwiftUI improvements ([#149](https://github.com/AckeeCZ/ACKategories/pull/149), kudos to @olejnjak)
- make `lineHeight` parameter optional for `FontModifier`
- implement color forwarding from UIKit to SwiftUI
- add `ACKHostingController`

## 6.14.0

- Add privacy manifest ([#148](https://github.com/AckeeCZ/ACKategories/pull/148), kudos to @olejnjak)
Expand Down
1 change: 1 addition & 0 deletions Sources/ACKategories/Base/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extension Base {
}
}

@available(*, unavailable)
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
Expand Down
53 changes: 53 additions & 0 deletions Sources/ACKategories/SwiftUIExtensions/ACKHostingController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#if !os(macOS) && !os(watchOS)
import os.log
import SwiftUI

@available(iOS 13.0, tvOS 13.0, *)
open class ACKHostingController<RootView: View>: UIHostingController<RootView> {
/// Navigation bar is shown/hidden in viewWillAppear according to this flag
public var hasNavigationBar = true

#if !os(tvOS)
public override var preferredStatusBarStyle: UIStatusBarStyle {
get { _preferredStatusBarStyle }
set {
_preferredStatusBarStyle = newValue
setNeedsStatusBarAppearanceUpdate()
}
}

private var _preferredStatusBarStyle: UIStatusBarStyle = .default
#endif

// MARK: - Initializers

public override init(rootView: RootView) {
super.init(rootView: rootView)

navigationItem.backButtonTitle = ""

if Base.memoryLoggingEnabled && Base.viewControllerMemoryLoggingEnabled {
os_log("📱 👶 %@", log: Logger.lifecycleLog(), type: .info, self)
}
}

@available(*, unavailable)
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

deinit {
if Base.memoryLoggingEnabled && Base.viewControllerMemoryLoggingEnabled {
os_log("📱 ⚰️ %@", log: Logger.lifecycleLog(), type: .info, self)
}
}

// MARK: - View life cycle

override open func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

navigationController?.setNavigationBarHidden(!hasNavigationBar, animated: animated)
}
}
#endif
26 changes: 10 additions & 16 deletions Sources/ACKategories/SwiftUIExtensions/FontModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,22 @@ public extension View {
/// - font: The font to use in this view.
/// - lineHeight: The line height to use in this view.
/// - textStyle: The text style for relative font scaling. If `nil`is specified then dynamic type is turned off.
func font(
@ViewBuilder func font(
_ font: UIFont,
lineHeight: Double,
lineHeight: Double?,
textStyle: Font.TextStyle?
) -> some View {
let customFont: Font

// Do not scale font based on dynamic type when nil `relativeTo` specified
if let textStyle = textStyle {
customFont = .custom(
font.fontName,
size: font.pointSize,
relativeTo: textStyle
)
let customFont = textStyle
.map { Font.custom(font.fontName, size: font.pointSize, relativeTo: $0) } ?? Font(font)

if let lineHeight {
self.font(customFont)
.lineSpacing(lineHeight - font.lineHeight)
.padding(.vertical, (lineHeight - font.lineHeight) / 2)
} else {
customFont = Font(font)
self.font(customFont)
}

return self
.font(customFont)
.lineSpacing(lineHeight - font.lineHeight)
.padding(.vertical, (lineHeight - font.lineHeight) / 2)
}
}
#endif
33 changes: 33 additions & 0 deletions Sources/ACKategories/SwiftUIExtensions/SwiftUIColorsTheme.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#if canImport(UIKit)
import SwiftUI
import UIKit

/// Using this namespace you can define your colors in ``Theme`` extension of `UIColor`
/// and they will automatically appear in `Color.theme` namespace.
///
/// Make sure your extensions are not defined as static, only instance variables with type `UIColor` will be bridged.
///
/// ## Example
///
/// ```swift
/// extension Theme<UIColor> {
/// var primary: UIColor { .red }
/// }
/// ```
///
/// Then you can use `Color.theme.primary` in SwiftUI
@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *)
@dynamicMemberLookup
public struct SwiftUIColorsTheme {
public subscript(dynamicMember keyPath: KeyPath<Theme<UIColor>, UIColor>) -> SwiftUI.Color {
let uiColor = Theme<UIColor>()[keyPath: keyPath]
return .init(uiColor)
}
}

@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *)
public extension Color {
/// Namespace for bridged ``Theme`` colors from `Theme<UIColor>` extension, see ``SwiftUIColorsTheme``.
static let theme = SwiftUIColorsTheme()
}
#endif
4 changes: 2 additions & 2 deletions Sources/ACKategories/UI/Theme/ThemeProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public struct Theme<Base> { }
public protocol ThemeProvider { }

public extension ThemeProvider {
static var theme: Theme<Self>.Type { Theme<Self>.self }
static var theme: Theme<Self> { Theme<Self>() } // theoretically unneccessary allocation overhead every call, but SnapKit uses the same pattern so...

var theme: Theme<Self> { Theme<Self>() } // theoretically unneccessary allocation overhead every call, but SnapKit uses the same pattern so...
var theme: Theme<Self> { Self.theme }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,10 @@ import ACKategories
import ACKategoriesTesting
import XCTest

@MainActor
@available(tvOS 13.0, iOS 13.0, watchOS 6.0, macOS 10.15, *)
final class VersionUpdateManager_Tests: XCTestCase {
private var fetcher: VersionUpdateFetcher_Mock!

// MARK: - Setup

override func setUp() {
fetcher = .init()
super.setUp()
}

func test_minBuildNumber_lower() async throws {
let fetcher = VersionUpdateFetcher_Mock()
let buildNumber = Int.random(in: 1..<10_000)

fetcher.minBuildNumber = buildNumber - 1
Expand All @@ -29,6 +20,7 @@ final class VersionUpdateManager_Tests: XCTestCase {
}

func test_minBuildNumber_equal() async throws {
let fetcher = VersionUpdateFetcher_Mock()
let buildNumber = Int.random(in: 1..<10_000)

fetcher.minBuildNumber = buildNumber
Expand All @@ -43,6 +35,7 @@ final class VersionUpdateManager_Tests: XCTestCase {
}

func test_minBuildNumber_higher() async throws {
let fetcher = VersionUpdateFetcher_Mock()
let buildNumber = Int.random(in: 1..<10_000)

fetcher.minBuildNumber = buildNumber + 1
Expand Down
Loading