Compare commits

..
Author SHA1 Message Date
Shin Yamamoto 8ab6007892 Set 'Explicitly Builts Modules' to 'YES' 2024-09-30 15:14:36 +09:00
10 changed files with 61 additions and 135 deletions

No files matched your search

+1 -30
View File
@@ -1,27 +1,6 @@
version: 2.1 version: 2.1
jobs: jobs:
build-swift_5_7:
macos:
xcode: 13.4.1
steps:
- checkout
- run: xcodebuild -scheme FloatingPanel -workspace FloatingPanel.xcworkspace SWIFT_VERSION=5.7 clean build
build-swiftpm_ios15_7:
macos:
xcode: 13.4.1
steps:
- checkout
- run: swift build -Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphonesimulator --show-sdk-path`" -Xswiftc "-target" -Xswiftc "x86_64-apple-ios15.7-simulator"
- run: swift build -Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphonesimulator --show-sdk-path`" -Xswiftc "-target" -Xswiftc "arm64-apple-ios15.7-simulator"
test-ios15_5-iPhone_13_Pro:
macos:
xcode: 13.4.1
steps:
- checkout
- run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=15.5,name=iPhone 13 Pro'
test-ios14_5-iPhone_12_Pro: test-ios14_5-iPhone_12_Pro:
macos: macos:
xcode: 13.4.1 xcode: 13.4.1
@@ -29,15 +8,7 @@ jobs:
- checkout - checkout
- run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=14.5,name=iPhone 12 Pro' - run: xcodebuild clean test -scheme FloatingPanel -workspace FloatingPanel.xcworkspace -destination 'platform=iOS Simulator,OS=14.5,name=iPhone 12 Pro'
workflows: workflows:
test: test:
jobs: jobs:
- build-swift_5_7: - test-ios14_5-iPhone_12_Pro
name: build (5.7, 13.4.1)
- build-swiftpm_ios15_7:
name: swiftpm ({x86_64,arm64}-apple-ios15.5-simulator, 13.4.1)
- test-ios14_5-iPhone_12_Pro:
name: test (15.5, 13.4.1, iPhone 12 Pro)
- test-ios15_5-iPhone_13_Pro:
name: test (14.5, 13.4.1, iPhone 13 Pro)
+29 -27
View File
@@ -18,9 +18,6 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- swift: "5"
xcode: "16.2"
runs-on: macos-15
- swift: "5.10" - swift: "5.10"
xcode: "15.4" xcode: "15.4"
runs-on: macos-14 runs-on: macos-14
@@ -30,6 +27,15 @@ jobs:
- swift: "5.8" - swift: "5.8"
xcode: "14.3.1" xcode: "14.3.1"
runs-on: macos-13 runs-on: macos-13
- swift: "5.7"
xcode: "14.1"
runs-on: macos-12
- swift: "5.6"
xcode: "13.4.1"
runs-on: macos-12
- swift: "5.5"
xcode: "13.2.1"
runs-on: macos-12
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Building in Swift ${{ matrix.swift }} - name: Building in Swift ${{ matrix.swift }}
@@ -43,11 +49,6 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: "18.2"
xcode: "16.2"
sim: "iPhone 16 Pro"
parallel: NO # Stop random test job failures
runs-on: macos-15
- os: "17.5" - os: "17.5"
xcode: "15.4" xcode: "15.4"
sim: "iPhone 15 Pro" sim: "iPhone 15 Pro"
@@ -58,6 +59,11 @@ jobs:
sim: "iPhone 14 Pro" sim: "iPhone 14 Pro"
parallel: NO # Stop random test job failures parallel: NO # Stop random test job failures
runs-on: macos-13 runs-on: macos-13
- os: "15.5"
xcode: "13.4.1"
sim: "iPhone 13 Pro"
parallel: NO # Stop random test job failures
runs-on: macos-12
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Testing in iOS ${{ matrix.os }} - name: Testing in iOS ${{ matrix.os }}
@@ -70,9 +76,9 @@ jobs:
timeout-minutes: 20 timeout-minutes: 20
example: example:
runs-on: macos-15 runs-on: macos-14
env: env:
DEVELOPER_DIR: /Applications/Xcode_16.2.app/Contents/Developer DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -84,7 +90,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Building ${{ matrix.example }} - name: Building ${{ matrix.example }}
# Need to use iphonesimulator18.1 because randomly 18.2<DVTBuildVersion 22C146> isn't available.
run: | run: |
xcodebuild clean build \ xcodebuild clean build \
-workspace FloatingPanel.xcworkspace \ -workspace FloatingPanel.xcworkspace \
@@ -92,32 +97,22 @@ jobs:
-sdk iphonesimulator -sdk iphonesimulator
swiftpm: swiftpm:
runs-on: macos-15 runs-on: macos-14
env: env:
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
xcode: ["16.2", "15.4"]
platform: [iphoneos, iphonesimulator] platform: [iphoneos, iphonesimulator]
arch: [x86_64, arm64] arch: [x86_64, arm64]
exclude: exclude:
- platform: iphoneos - platform: iphoneos
arch: x86_64 arch: x86_64
include: include:
# 18.2
- platform: iphoneos
xcode: "16.2"
sys: "ios18.2"
- platform: iphonesimulator
xcode: "16.2"
sys: "ios18.2-simulator"
# 17.2 # 17.2
- platform: iphoneos - platform: iphoneos
xcode: "15.4"
sys: "ios17.2" sys: "ios17.2"
- platform: iphonesimulator - platform: iphonesimulator
xcode: "15.4"
sys: "ios17.2-simulator" sys: "ios17.2-simulator"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -142,6 +137,13 @@ jobs:
- target: "arm64-apple-ios16.4-simulator" - target: "arm64-apple-ios16.4-simulator"
xcode: "14.3.1" xcode: "14.3.1"
runs-on: macos-13 runs-on: macos-13
# 15.7
- target: "x86_64-apple-ios15.7-simulator"
xcode: "14.1"
runs-on: macos-12
- target: "arm64-apple-ios15.7-simulator"
xcode: "14.1"
runs-on: macos-12
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: "Swift Package Manager build" - name: "Swift Package Manager build"
@@ -151,12 +153,12 @@ jobs:
-Xswiftc "-target" -Xswiftc "${{ matrix.target }}" -Xswiftc "-target" -Xswiftc "${{ matrix.target }}"
cocoapods: cocoapods:
runs-on: macos-15 runs-on: macos-14
env: env:
DEVELOPER_DIR: /Applications/Xcode_16.2.app/Contents/Developer DEVELOPER_DIR: /Applications/Xcode_15.4.app/Contents/Developer
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: "CocoaPods: pod lib lint" - name: "CocoaPods: pod lib lint"
run: pod lib lint --allow-warnings --verbose run: pod lib lint --allow-warnings
- name: "CocoaPods: pod spec lint" - name: "CocoaPods: pod spec lint"
run: pod spec lint --allow-warnings --verbose run: pod spec lint --allow-warnings
@@ -202,10 +202,10 @@ extension UseCaseController {
fpc.set(contentViewController: contentVC) fpc.set(contentViewController: contentVC)
fpc.delegate = self fpc.delegate = self
let appearance = SurfaceAppearance() let apprearance = SurfaceAppearance()
appearance.cornerRadius = 38.5 apprearance.cornerRadius = 38.5
appearance.shadows = [] apprearance.shadows = []
fpc.surfaceView.appearance = appearance fpc.surfaceView.appearance = apprearance
fpc.isRemovalInteractionEnabled = true fpc.isRemovalInteractionEnabled = true
let mvc = UIViewController() let mvc = UIViewController()
+2 -2
View File
@@ -1,7 +1,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = "FloatingPanel" s.name = "FloatingPanel"
s.version = "2.8.7" s.version = "2.8.6"
s.summary = "FloatingPanel is a clean and easy-to-use UI component of a floating panel interface." s.summary = "FloatingPanel is a clean and easy-to-use UI component of a floating panel interface."
s.description = <<-DESC s.description = <<-DESC
FloatingPanel is a clean and easy-to-use UI component for a new interface introduced in Apple Maps, Shortcuts and Stocks app. FloatingPanel is a clean and easy-to-use UI component for a new interface introduced in Apple Maps, Shortcuts and Stocks app.
@@ -9,7 +9,7 @@ The new interface displays the related contents and utilities in parallel as a u
DESC DESC
s.homepage = "https://github.com/scenee/FloatingPanel" s.homepage = "https://github.com/scenee/FloatingPanel"
s.author = "Shin Yamamoto" s.author = "Shin Yamamoto"
s.social_media_url = "https://x.com/scenee" s.social_media_url = "https://twitter.com/scenee"
s.platform = :ios, "11.0" s.platform = :ios, "11.0"
s.source = { :git => "https://github.com/scenee/FloatingPanel.git", :tag => s.version.to_s } s.source = { :git => "https://github.com/scenee/FloatingPanel.git", :tag => s.version.to_s }
+3
View File
@@ -477,6 +477,7 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES;
}; };
name = Debug; name = Debug;
}; };
@@ -507,6 +508,7 @@
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES;
}; };
name = Release; name = Release;
}; };
@@ -646,6 +648,7 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
_EXPERIMENTAL_SWIFT_EXPLICIT_MODULES = YES;
}; };
name = Test; name = Test;
}; };
+1 -1
View File
@@ -8,7 +8,7 @@
FloatingPanel is a simple and easy-to-use UI component designed for a user interface featured in Apple Maps, Shortcuts and Stocks app. FloatingPanel is a simple and easy-to-use UI component designed for a user interface featured in Apple Maps, Shortcuts and Stocks app.
The user interface displays related content and utilities alongside the main content. The user interface displays related content and utilities alongside the main content.
Please see also [the API reference@SPI](https://swiftpackageindex.com/scenee/FloatingPanel/2.8.7/documentation/floatingpanel) for more details. Please see also [the API reference@SPI](https://swiftpackageindex.com/scenee/FloatingPanel/2.8.6/documentation/floatingpanel) for more details.
![Maps](https://github.com/SCENEE/FloatingPanel/blob/master/assets/maps.gif) ![Maps](https://github.com/SCENEE/FloatingPanel/blob/master/assets/maps.gif)
![Stocks](https://github.com/SCENEE/FloatingPanel/blob/master/assets/stocks.gif) ![Stocks](https://github.com/SCENEE/FloatingPanel/blob/master/assets/stocks.gif)
+20 -31
View File
@@ -71,7 +71,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
var removalVector: CGVector = .zero var removalVector: CGVector = .zero
// Scroll handling // Scroll handling
private var initialScrollOffset: CGPoint? private var initialScrollOffset: CGPoint = .zero
private var scrollBounce = false private var scrollBounce = false
private var scrollIndictorVisible = false private var scrollIndictorVisible = false
private var scrollBounceThreshold: CGFloat = -30.0 private var scrollBounceThreshold: CGFloat = -30.0
@@ -411,7 +411,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
if insideMostExpandedAnchor { if insideMostExpandedAnchor {
// Prevent scrolling if needed // Prevent scrolling if needed
if isScrollable(state: state), let initialScrollOffset = initialScrollOffset { if isScrollable(state: state) {
if interactionInProgress { if interactionInProgress {
os_log(msg, log: devLog, type: .debug, "settle offset -- \(value(of: initialScrollOffset))") os_log(msg, log: devLog, type: .debug, "settle offset -- \(value(of: initialScrollOffset))")
// Return content offset to initial offset to prevent scrolling // Return content offset to initial offset to prevent scrolling
@@ -429,7 +429,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
stopScrolling(at: initialScrollOffset) stopScrolling(at: initialScrollOffset)
} }
} }
} else if let initialScrollOffset = initialScrollOffset { } else {
// Return content offset to initial offset to prevent scrolling // Return content offset to initial offset to prevent scrolling
stopScrolling(at: initialScrollOffset) stopScrolling(at: initialScrollOffset)
} }
@@ -471,8 +471,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
} }
if isScrollable(state: state) { if isScrollable(state: state) {
// Adjust a small gap of the scroll offset just after swiping down starts in the grabber area. // Adjust a small gap of the scroll offset just after swiping down starts in the grabber area.
if surfaceView.grabberAreaContains(location), surfaceView.grabberAreaContains(initialLocation), if surfaceView.grabberAreaContains(location), surfaceView.grabberAreaContains(initialLocation) {
let initialScrollOffset = initialScrollOffset {
stopScrolling(at: initialScrollOffset) stopScrolling(at: initialScrollOffset)
} }
} }
@@ -500,8 +499,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
} }
} }
// Adjust a small gap of the scroll offset just before swiping down starts in the grabber area, // Adjust a small gap of the scroll offset just before swiping down starts in the grabber area,
if surfaceView.grabberAreaContains(location), surfaceView.grabberAreaContains(initialLocation), if surfaceView.grabberAreaContains(location), surfaceView.grabberAreaContains(initialLocation) {
let initialScrollOffset = initialScrollOffset {
stopScrolling(at: initialScrollOffset) stopScrolling(at: initialScrollOffset)
} }
} }
@@ -610,7 +608,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
guard guard
isScrollable(state: state), // When not top most(i.e. .full), don't scroll. isScrollable(state: state), // When not top most(i.e. .full), don't scroll.
interactionInProgress == false, // When interaction already in progress, don't scroll. interactionInProgress == false, // When interaction already in progress, don't scroll.
abs(layoutAdapter.offset(from: state)) < 1, // Indistinguishably close to an anchor point. 0 == layoutAdapter.offset(from: state),
!surfaceView.grabberAreaContains(initialLocation) // When the initial point is within grabber area, don't scroll !surfaceView.grabberAreaContains(initialLocation) // When the initial point is within grabber area, don't scroll
else { else {
return false return false
@@ -849,7 +847,7 @@ class Core: NSObject, UIGestureRecognizerDelegate {
} else { } else {
initialScrollOffset = scrollView.contentOffset initialScrollOffset = scrollView.contentOffset
} }
os_log(msg, log: devLog, type: .debug, "initial scroll offset -- \(optional: initialScrollOffset)") os_log(msg, log: devLog, type: .debug, "initial scroll offset -- \(initialScrollOffset)")
} }
initialTranslation = translation initialTranslation = translation
@@ -896,6 +894,17 @@ class Core: NSObject, UIGestureRecognizerDelegate {
return true return true
} }
func endWithoutAttraction(_ target: FloatingPanelState) {
self.state = target
self.updateLayout(to: target)
self.unlockScrollView()
// The `floatingPanelDidEndDragging(_:willAttract:)` must be called after the state property changes.
// This allows library users to get the correct state in the delegate method.
if let vc = ownerVC {
vc.delegate?.floatingPanelDidEndDragging?(vc, willAttract: false)
}
}
private func startAttraction(to state: FloatingPanelState, with velocity: CGPoint, completion: @escaping (() -> Void)) { private func startAttraction(to state: FloatingPanelState, with velocity: CGPoint, completion: @escaping (() -> Void)) {
os_log(msg, log: devLog, type: .debug, "startAnimation to \(state) -- velocity = \(value(of: velocity))") os_log(msg, log: devLog, type: .debug, "startAnimation to \(state) -- velocity = \(value(of: velocity))")
guard let vc = ownerVC else { return } guard let vc = ownerVC else { return }
@@ -925,8 +934,8 @@ class Core: NSObject, UIGestureRecognizerDelegate {
self.backdropView.alpha = self.getBackdropAlpha(at: current, with: translation) self.backdropView.alpha = self.getBackdropAlpha(at: current, with: translation)
// Pin the offset of the tracking scroll view while moving by this animator // Pin the offset of the tracking scroll view while moving by this animator
if let scrollView = self.scrollView, let initialScrollOffset = self.initialScrollOffset { if let scrollView = self.scrollView {
self.stopScrolling(at: initialScrollOffset) self.stopScrolling(at: self.initialScrollOffset)
os_log(msg, log: devLog, type: .debug, "move -- pinning scroll offset = \(scrollView.contentOffset)") os_log(msg, log: devLog, type: .debug, "move -- pinning scroll offset = \(scrollView.contentOffset)")
} }
@@ -950,12 +959,6 @@ class Core: NSObject, UIGestureRecognizerDelegate {
self.isAttracting = false self.isAttracting = false
self.moveAnimator = nil self.moveAnimator = nil
// We need to reset `initialScrollOffset` because the scroll offset can become unexpected
// under the following circumstances:
// 1. The scroll offset changes while the panel does not move.
// 2. The panel is then moved using `move(to:animate:completion:)`.
self.initialScrollOffset = nil
if let vc = ownerVC { if let vc = ownerVC {
vc.delegate?.floatingPanelDidEndAttracting?(vc) vc.delegate?.floatingPanelDidEndAttracting?(vc)
} }
@@ -978,20 +981,6 @@ class Core: NSObject, UIGestureRecognizerDelegate {
} }
} }
func endWithoutAttraction(_ target: FloatingPanelState) {
// See comments in `endAttraction`
self.initialScrollOffset = nil
self.state = target
self.updateLayout(to: target)
self.unlockScrollView()
// The `floatingPanelDidEndDragging(_:willAttract:)` must be called after the state property changes.
// This allows library users to get the correct state in the delegate method.
if let vc = ownerVC {
vc.delegate?.floatingPanelDidEndDragging?(vc, willAttract: false)
}
}
func value(of point: CGPoint) -> CGFloat { func value(of point: CGPoint) -> CGFloat {
return layoutAdapter.position.mainLocation(point) return layoutAdapter.position.mainLocation(point)
} }
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.8.7</string> <string>2.8.6</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
</dict> </dict>
-11
View File
@@ -15,14 +15,3 @@ struct Logging {
static let category = "FloatingPanel" static let category = "FloatingPanel"
private init() {} private init() {}
} }
extension String.StringInterpolation {
mutating func appendInterpolation<T>(optional: T?, defaultValue: String = "nil") {
switch optional {
case let value?:
appendLiteral(String(describing: value))
case nil:
appendLiteral(defaultValue)
}
}
}
-28
View File
@@ -916,34 +916,6 @@ class CoreTests: XCTestCase {
} }
} }
func test_initial_scroll_offset_reset() {
let fpc = FloatingPanelController()
let scrollView = UIScrollView()
fpc.layout = FloatingPanelBottomLayout()
fpc.track(scrollView: scrollView)
fpc.showForTest()
fpc.move(to: .full, animated: false)
fpc.panGestureRecognizer.state = .began
fpc.floatingPanel.handle(panGesture: fpc.panGestureRecognizer)
fpc.panGestureRecognizer.state = .cancelled
fpc.floatingPanel.handle(panGesture: fpc.panGestureRecognizer)
waitRunLoop(secs: 1.0)
let expect = CGPoint(x: 0, y: 100)
scrollView.setContentOffset(expect, animated: false)
fpc.move(to: .half, animated: true)
waitRunLoop(secs: 1.0)
XCTAssertEqual(expect, scrollView.contentOffset)
}
func test_handleGesture_endWithoutAttraction() throws { func test_handleGesture_endWithoutAttraction() throws {
class Delegate: FloatingPanelControllerDelegate { class Delegate: FloatingPanelControllerDelegate {
var willAttract: Bool? var willAttract: Bool?