Skip to content

Commit

Permalink
Fixed build errors for macOS by adjusting availability of functions t…
Browse files Browse the repository at this point in the history
…o iOS only and changing availability of the package to macOS 11 or later.

WidgetSize parameters and methods referencing current device sizes moved to a separate file and made only available on iOS.
Moved OverlappingImage to a folder and moved the UIImage inits to a separate file.
Removed the example test that cause build crashes.
Added Swift Package Index badges.
  • Loading branch information
ryanlintott committed Jan 25, 2022
1 parent 1c1c47e commit 03acfb1
Show file tree
Hide file tree
Showing 12 changed files with 125 additions and 90 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let package = Package(
name: "FrameUp",
platforms: [
.iOS(.v14),
.macOS(.v10_15)
.macOS(.v11)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<img height="128" alt="FrameUp Logo" src="https://user-images.githubusercontent.com/2143656/149010960-2b0e1200-b6d4-40a5-bbe7-4aabc5ce6b09.png">

![Platform iOS 14](https://img.shields.io/badge/platform-iOS%2014-blue.svg)
[![SPM compatible](https://img.shields.io/badge/SPM-compatible-4BC51D.svg?style=flat)](https://github.com/apple/swift-package-manager)
[![Swift Compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fryanlintott%2FFrameUp%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/ryanlintott/FrameUp)
[![Platform Compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fryanlintott%2FFrameUp%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/ryanlintott/FrameUp)
![License - MIT](https://img.shields.io/github/license/ryanlintott/FrameUp)
![Version](https://img.shields.io/github/v/tag/ryanlintott/FrameUp?label=version)
![GitHub last commit](https://img.shields.io/github/last-commit/ryanlintott/FrameUp)
Expand Down Expand Up @@ -33,7 +33,7 @@ Check out the example app to see how you can use this package in your iOS app.
Import the package using `import FrameUp`

# Platforms
This package is compatible with iOS 14 or later. It's technically compatible with macOS 10.15 but hasn't been tested yet.
This package is compatible with iOS 14 or later. It's technically compatible with macOS 11 but hasn't been tested yet.

# Is this Production-Ready?
Really it's up to you. I currently use this package in my own [Old English Wordhord app](https://oldenglishwordhord.com/app).
Expand Down
30 changes: 30 additions & 0 deletions Sources/FrameUp/Images/OverlappingImage+UIImage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// OverlappingImage+UIImage.swift
// FrameUp
//
// Created by Ryan Lintott on 2022-01-25.
//

import SwiftUI

#if canImport(UIKit)
extension OverlappingImage {
/// Creates an image view that overlaps content at the edges of its frame
/// - Parameters:
/// - uiImage: Image that will overlap content.
/// - top: Overlap percent at top edge.
/// - bottom: Overlap percent at bottom edge.
public init(uiImage: UIImage, top: CGFloat = 0, bottom: CGFloat = 0) {
self.init(Image(uiImage: uiImage), aspectRatio: uiImage.size.aspectRatio, top: top, bottom: bottom)
}

/// Creates an image view that overlaps content at the edges of its frame
/// - Parameters:
/// - uiImage: Image that will overlap content.
/// - left: Overlap percent at left edge.
/// - right: Overlap percent at right edge.
public init(uiImage: UIImage, left: CGFloat = 0, right: CGFloat = 0) {
self.init(Image(uiImage: uiImage), aspectRatio: uiImage.size.aspectRatio, left: left, right: right)
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,6 @@ public struct OverlappingImage: View {
self.newAspect = aspectRatio * newWidthPercent
}

/// Creates an image view that overlaps content at the edges of its frame
/// - Parameters:
/// - uiImage: Image that will overlap content.
/// - top: Overlap percent at top edge.
/// - bottom: Overlap percent at bottom edge.
public init(uiImage: UIImage, top: CGFloat = 0, bottom: CGFloat = 0) {
self.init(Image(uiImage: uiImage), aspectRatio: uiImage.size.aspectRatio, top: top, bottom: bottom)
}

/// Creates an image view that overlaps content at the edges of its frame
/// - Parameters:
/// - uiImage: Image that will overlap content.
/// - left: Overlap percent at left edge.
/// - right: Overlap percent at right edge.
public init(uiImage: UIImage, left: CGFloat = 0, right: CGFloat = 0) {
self.init(Image(uiImage: uiImage), aspectRatio: uiImage.size.aspectRatio, left: left, right: right)
}

public var body: some View {
Color.clear
.overlay(
Expand Down
2 changes: 2 additions & 0 deletions Sources/FrameUp/WidgetSize/FixWidgetPreviewAlignmentBug.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import SwiftUI
import WidgetKit

#if os(iOS)
/// *Not working yet!* View modifier that will adjust the widget's position in SwiftUI Previews
///
/// Attempts to fix the widget preview alignment bug
Expand Down Expand Up @@ -64,3 +65,4 @@ public extension View {
self.modifier(FixWidgetPreviewAlignmentBug(adjustment: adjustment))
}
}
#endif
4 changes: 3 additions & 1 deletion Sources/FrameUp/WidgetSize/WidgetDemoFrame.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public struct WidgetDemoFrame<Content: View>: View {

public var body: some View {
Group {
if #available(iOS 15.0, *) {
if #available(iOS 15.0, macOS 12, *) {
content(designCanvasSize, designCornerRadius)
.containerShape(widgetShape)
} else {
Expand All @@ -55,6 +55,7 @@ public struct WidgetDemoFrame<Content: View>: View {
.scaledToFrame(homeScreenSize, contentMode: .fit) }
}

#if os(iOS)
public extension WidgetDemoFrame {
/// Creates a widget demo view for a specified widget size and corner radius for the current device.
/// - Parameters:
Expand All @@ -70,3 +71,4 @@ public extension WidgetDemoFrame {
)
}
}
#endif
4 changes: 3 additions & 1 deletion Sources/FrameUp/WidgetSize/WidgetFamily+extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import SwiftUI
import WidgetKit

public extension WidgetFamily {
#if os(iOS)
/// Supported families for the current device.
static var supportedFamiliesForCurrentDevice: [WidgetFamily] {
WidgetSize.supportedSizesForCurrentDevice.compactMap { $0.widgetFamily }
}

#endif

/// Equivalent widget size. Only returns nil for unknown values.
var size: WidgetSize? {
switch self {
Expand Down
2 changes: 2 additions & 0 deletions Sources/FrameUp/WidgetSize/WidgetRelativeShape.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import WidgetKit
import SwiftUI

#if os(iOS)
@available(iOS, unavailable)
@available(iOSApplicationExtension 14.0, *)
/// A scalable version of ContainerRelativeShape.
Expand Down Expand Up @@ -50,3 +51,4 @@ public extension ScaledShape where Content == ScaledContainerRelativeShape {
self.init(shape: ScaledContainerRelativeShape(scaleFactor: scaleFactor), scale: scaleSize, anchor: .topLeading)
}
}
#endif
75 changes: 75 additions & 0 deletions Sources/FrameUp/WidgetSize/WidgetSize+CurrentDevice.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// WidgetSize+CurrentDevice.swift
// FrameUp
//
// Created by Ryan Lintott on 2022-01-25.
//

import SwiftUI

#if os(iOS)
public extension WidgetSize {
/// The screen size ignoring orientation.
private static let currentScreenSize = UIScreen.main.fixedCoordinateSpace.bounds.size

/// The current device.
private static let currentDevice = UIDevice.current.userInterfaceIdiom

/// Find the supported sizes for a specified device
/// - Parameter device: iPhone, iPad, etc
/// - Returns: An array of widget sizes
static func supportedSizes(for device: UIUserInterfaceIdiom) -> [WidgetSize] {
switch device {
case .pad:
if #available(iOS 15.0, *) {
return [.small, .medium, .large, .extraLarge]
} else {
fallthrough
}
case .phone:
return [.small, .medium, .large]
default:
return []
}
}

/// Supported widget sizes for the current device.
static var supportedSizesForCurrentDevice: [WidgetSize] {
supportedSizes(for: currentDevice)
}

/// Size for this widget on the current device.
/// - Parameter iPadTarget: Widget frame target. iPad widgets have a design canvas frame used for laying out the content, and a smaller Home Screen frame that the content is scaled to fit.
/// - Returns: Size for this widget for the current device. Zero if device does not have widgets or if no size is available.
func sizeForCurrentDevice(iPadTarget: WidgetTarget = .homeScreen) -> CGSize {
switch Self.currentDevice {
case .pad:
return sizeForiPad(screenSize: Self.currentScreenSize, target: iPadTarget)
case .phone:
return sizeForiPhone(screenSize: Self.currentScreenSize)
default:
return .zero
}
}

/// How much the widget is scaled down to fit on the Home Screen.
///
/// Home Screen width divided by design canvas width
/// - Parameter screenSize: iPad screen size ignoring orientation.
/// - Returns: Widget scale factor between design canvas and Home Screen.
func scaleFactorForiPad(screenSize: CGSize) -> CGFloat {
sizeForiPad(screenSize: Self.currentScreenSize, target: .homeScreen).width / sizeForiPad(screenSize: Self.currentScreenSize, target: .designCanvas).width
}

/// How much the widget is scaled down to fit on the Home Screen.
///
/// Home Screen width divided by design canvas width. iPhone value will always be 1.
var scaleFactorForCurrentDevice: CGFloat {
guard Self.currentDevice == .pad else {
return 1
}

return scaleFactorForiPad(screenSize: Self.currentScreenSize)
}
}
#endif
8 changes: 6 additions & 2 deletions Sources/FrameUp/WidgetSize/WidgetSize+WidgetKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ import Foundation
import WidgetKit

public extension WidgetSize {
/// Equivalent widget family. Optional as extraLarge will return nil unless running iOS 15.0 or later.
/// Equivalent widget family. Optional as extraLarge will return nil unless running iOS 15.0 or later or macOS 12 or later.
var widgetFamily: WidgetFamily? {
switch self {
case .small: return .systemSmall
case .medium: return .systemMedium
case .large: return .systemLarge
case .extraLarge:
if #available(iOS 15.0, *) {
return .systemExtraLarge
#if os(iOS)
return .systemExtraLarge
#else
return nil
#endif
} else {
return nil
}
Expand Down
63 changes: 0 additions & 63 deletions Sources/FrameUp/WidgetSize/WidgetSize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,6 @@ public enum WidgetTarget {
}

public extension WidgetSize {
/// The screen size ignoring orientation.
private static let currentScreenSize = UIScreen.main.fixedCoordinateSpace.bounds.size

/// The current device.
private static let currentDevice = UIDevice.current.userInterfaceIdiom

/// Find the supported sizes for a specified device
/// - Parameter device: iPhone, iPad, etc
/// - Returns: An array of widget sizes
static func supportedSizes(for device: UIUserInterfaceIdiom) -> [WidgetSize] {
switch device {
case .pad:
if #available(iOS 15.0, *) {
return [.small, .medium, .large, .extraLarge]
} else {
fallthrough
}
case .phone:
return [.small, .medium, .large]
default:
return []
}
}

/// Supported widget sizes for the current device.
static var supportedSizesForCurrentDevice: [WidgetSize] {
supportedSizes(for: currentDevice)
}

/// Smallest widget size possibe for each WidgetFamily
static let minimumSizes: [WidgetSize: CGSize] = [
.small: CGSize(width: 141, height: 141),
Expand Down Expand Up @@ -153,40 +124,6 @@ public extension WidgetSize {
func sizeForiPad(screenSize: CGSize, target: WidgetTarget) -> CGSize {
Self.sizesForiPad(screenSize: screenSize, target: target)[self] ?? .zero
}


/// Size for this widget on the current device.
/// - Parameter iPadTarget: Widget frame target. iPad widgets have a design canvas frame used for laying out the content, and a smaller Home Screen frame that the content is scaled to fit.
/// - Returns: Size for this widget for the current device. Zero if device does not have widgets or if no size is available.
func sizeForCurrentDevice(iPadTarget: WidgetTarget = .homeScreen) -> CGSize {
switch Self.currentDevice {
case .pad:
return sizeForiPad(screenSize: Self.currentScreenSize, target: iPadTarget)
case .phone:
return sizeForiPhone(screenSize: Self.currentScreenSize)
default:
return .zero
}
}

/// How much the widget is scaled down to fit on the Home Screen.
///
/// Home Screen width divided by design canvas width
/// - Parameter screenSize: iPad screen size ignoring orientation.
/// - Returns: Widget scale factor between design canvas and Home Screen.
func scaleFactorForiPad(screenSize: CGSize) -> CGFloat {
sizeForiPad(screenSize: Self.currentScreenSize, target: .homeScreen).width / sizeForiPad(screenSize: Self.currentScreenSize, target: .designCanvas).width
}

/// How much the widget is scaled down to fit on the Home Screen.
///
/// Home Screen width divided by design canvas width. iPhone value will always be 1.
var scaleFactorForCurrentDevice: CGFloat {
guard Self.currentDevice == .pad else {
return 1
}

return scaleFactorForiPad(screenSize: Self.currentScreenSize)
}
}

1 change: 0 additions & 1 deletion Tests/FrameUpTests/FrameUpTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ final class FrameUpTests: XCTestCase {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(FrameUp().text, "Hello, World!")
}
}

0 comments on commit 03acfb1

Please sign in to comment.