Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
fail-fast: false
matrix:
include:
- os: "26.0"
- os: "26.0.1"
xcode: "26.0.1"
sim: "iPhone 16 Pro"
parallel: NO # Stop random test job failures
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import FloatingPanel
import SwiftUI
import UIKit
import os.log

struct MainView: View {
@State private var panelLayout: FloatingPanelLayout? = MyFloatingPanelLayout()
Expand All @@ -20,6 +21,9 @@ struct MainView: View {
.floatingPanelSurfaceAppearance(.transparent())
.floatingPanelLayout(panelLayout)
.floatingPanelState($panelState)
.onChange(of: panelState) { newValue in
Logger().debug("Panel state changed: \(newValue ?? .hidden)")
}

VStack(spacing: 32) {
Button("Move to full") {
Expand Down
3 changes: 2 additions & 1 deletion FloatingPanel.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The new interface displays the related contents and utilities in parallel as a u
s.author = "Shin Yamamoto"
s.social_media_url = "https://x.com/scenee"

s.platform = :ios, "13.0"
s.platform = :ios, "12.0"
s.source = { :git => "https://github.com/scenee/FloatingPanel.git", :tag => s.version.to_s }
s.source_files = "Sources/**/*.swift"
s.swift_version = '5.0'
Expand All @@ -20,3 +20,4 @@ The new interface displays the related contents and utilities in parallel as a u

s.license = { :type => "MIT", :file => "LICENSE" }
end

6 changes: 3 additions & 3 deletions FloatingPanel.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES;
INFOPLIST_FILE = Sources/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -556,7 +556,7 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES;
INFOPLIST_FILE = Sources/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -694,7 +694,7 @@
ENABLE_USER_SCRIPT_SANDBOXING = YES;
INFOPLIST_FILE = Sources/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import PackageDescription
let package = Package(
name: "FloatingPanel",
platforms: [
.iOS(.v13)
.iOS(.v12)
],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
Expand All @@ -25,3 +25,4 @@ let package = Package(
],
swiftLanguageVersions: [.version("5")]
)

18 changes: 16 additions & 2 deletions Sources/Core.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2018-Present Shin Yamamoto. All rights reserved. MIT license.

#if canImport(Combine)
import Combine
#endif
import UIKit
import os.log

Expand Down Expand Up @@ -50,7 +52,13 @@ class Core: NSObject, UIGestureRecognizerDelegate {
}
}
}
private(set) var statePublisher: CurrentValueSubject<FloatingPanelState, Never> = .init(.hidden)

@available(iOS 13.0, *)
private(set) var statePublisher: CurrentValueSubject<FloatingPanelState, Never>? {
get { _statePublisher as? CurrentValueSubject<FloatingPanelState, Never> }
set { _statePublisher = newValue }
}
private var _statePublisher: Any?

var panGestureRecognizer: FloatingPanelPanGestureRecognizer
let panGestureDelegateRouter: FloatingPanelPanGestureRecognizer.DelegateRouter
Expand Down Expand Up @@ -100,6 +108,10 @@ class Core: NSObject, UIGestureRecognizerDelegate {

super.init()

if #available(iOS 13.0, *) {
statePublisher = .init(.hidden)
}

panGestureRecognizer.set(floatingPanel: self)
surfaceView.addGestureRecognizer(panGestureRecognizer)
panGestureRecognizer.addTarget(self, action: #selector(handle(panGesture:)))
Expand Down Expand Up @@ -262,7 +274,9 @@ class Core: NSObject, UIGestureRecognizerDelegate {
layoutAdapter.activateLayout(for: target, forceLayout: true)
backdropView.alpha = getBackdropAlpha(for: target)
adjustScrollContentInsetIfNeeded()
statePublisher.send(target)
if #available(iOS 13.0, *) {
statePublisher?.send(target)
}
}

private func getBackdropAlpha(for target: FloatingPanelState) -> CGFloat {
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftUI/FloatingPanelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ extension FloatingPanelCoordinatorProxy {

/// Start observing ``FloatingPanelController/state`` through the `Core` object.
func observeStateChanges() {
controller.floatingPanel.statePublisher
controller.floatingPanel.statePublisher?
.sink { [weak self] state in
guard let self = self else { return }
// Needs to update the state binding value on the next run loop cycle to avoid this error.
Expand Down
42 changes: 42 additions & 0 deletions Tests/CoreTests.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Copyright 2018 the FloatingPanel authors. All rights reserved. MIT license.

import XCTest
#if canImport(Combine)
import Combine
#endif
@testable import FloatingPanel

class CoreTests: XCTestCase {
Expand Down Expand Up @@ -1022,6 +1025,45 @@ class CoreTests: XCTestCase {
XCTAssertEqual(fpc.surfaceLocation(for: .full).y, fpc.surfaceLocation.y)
XCTAssertEqual(delegate.willAttract, false)
}

@available(iOS 13.0, *)
func test_statePublisher() throws {
let fpc = FloatingPanelController()
fpc.showForTest()

XCTAssertEqual(fpc.state, .half)

// Verify statePublisher is available on iOS 13+
XCTAssertNotNil(fpc.floatingPanel.statePublisher)

var receivedStates: [FloatingPanelState] = []
var cancellables = Set<AnyCancellable>()

// Subscribe to statePublisher
fpc.floatingPanel.statePublisher?
.sink { state in
receivedStates.append(state)
}
.store(in: &cancellables)

// The initial state should be emitted first
XCTAssertEqual(receivedStates, [.half])

// Move to .full
fpc.move(to: .full, animated: false)
XCTAssertEqual(fpc.state, .full)
XCTAssertEqual(receivedStates, [.half, .full])

// Move to .tip
fpc.move(to: .tip, animated: false)
XCTAssertEqual(fpc.state, .tip)
XCTAssertEqual(receivedStates, [.half, .full, .tip])

// Move back to .half
fpc.move(to: .half, animated: false)
XCTAssertEqual(fpc.state, .half)
XCTAssertEqual(receivedStates, [.half, .full, .tip, .half])
}
}

private class FloatingPanelLayout3Positions: FloatingPanelTestLayout {
Expand Down
Loading