Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2e09e22
POS Modularization: Move core utilities to WooFoundationCore
staskus Sep 16, 2025
8f7edb4
POS Modularization: Move SwiftUI view modifiers to WooFoundation
staskus Sep 16, 2025
e95182d
POS Modularization: Move SwiftUI UI components to WooFoundation
staskus Sep 16, 2025
a2afa8f
POS Modularization: Move analytics infrastructure to WooFoundationCore
staskus Sep 16, 2025
bb2fce8
POS Modularization: Move business logic to Yosemite
staskus Sep 16, 2025
45d8b16
POS Modularization: Move connectivity utilities to WooFoundation
staskus Sep 16, 2025
3db5630
POS Modularization: Create dependency abstraction protocols and adaptors
staskus Sep 16, 2025
4c55196
POS Modularization: Update POS code with dependency injection
staskus Sep 16, 2025
541baa3
POS Modularization: Add POS-specific extensions and cleanup
staskus Sep 16, 2025
becc6a7
POS Modularization: Update main app files with new module imports
staskus Sep 16, 2025
9120e4b
POS Modularization: Update POS test files and mocks
staskus Sep 16, 2025
db81fe3
POS Modularization: Update Xcode project file
staskus Sep 16, 2025
25a6085
POS Modularization: Complete remaining file updates
staskus Sep 16, 2025
19a31f6
Merge branch 'trunk' into woomob-935-woo-pos-hack-week-pos-modulariza…
staskus Sep 16, 2025
ac5bbc7
Reset periphery baseline due to a lot of false-positives after moving…
staskus Sep 16, 2025
7de0c31
Remove unused code
staskus Sep 16, 2025
cbce231
Update PointOfSaleOrderControllerTests.swift
staskus Sep 16, 2025
bd8b367
Remove ServiceLocator dependency in new features
staskus Sep 16, 2025
3a0301d
Update RELEASE-NOTES.txt
staskus Sep 16, 2025
57d0c68
Revert Package.resolved
staskus Sep 16, 2025
bf7fd6f
Remove @available(iOS 17.0, *)
staskus Sep 16, 2025
1cd63ca
Fix PointOfSaleItemsControllerTests identation
staskus Sep 17, 2025
925a365
Remove unused or duplicate methods from String+Helpers
staskus Sep 17, 2025
6e23e39
Make orderTotal private in PointOfSaleCollectCashView
staskus Sep 17, 2025
9e603b5
Remove receipt non-eligible banner since POS only supports versions t…
staskus Sep 17, 2025
187d0c6
Remove unused SwiftUI import
staskus Sep 17, 2025
3260430
Remove unused CurrencySettings import
staskus Sep 17, 2025
23e59ee
Remove optional return
staskus Sep 17, 2025
6e6afbe
Revert to track pointOfSaleCheckoutCashPaymentTapped
staskus Sep 17, 2025
7efe91e
Make PreviewOnboardingViewFactoryConfiguration final
staskus Sep 17, 2025
6bfc4eb
Create an extension for optional parameters tracking in POSAnalyticsP…
staskus Sep 17, 2025
c1fdc2b
Revert PointOfSaleAggregateModelTests
staskus Sep 17, 2025
7037fc3
Remove isEligibleForPointOfSaleReceipts
staskus Sep 17, 2025
e4f2117
Rename OnboardingViewFactory to OnboardingViewContainer
staskus Sep 17, 2025
9da0a71
Address periphery warning
staskus Sep 17, 2025
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
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import SwiftUI

public struct IndefiniteCircularProgressViewStyle: ProgressViewStyle {
var size: CGFloat
var lineWidth: CGFloat = Constants.lineWidth
var lineCap: CGLineCap = .round
var circleColor: Color = Color(.primaryButtonBackground).opacity(Constants.backgroundOpacity)
var fillColor: Color = Color(.primaryButtonBackground)
public var size: CGFloat
public var lineWidth: CGFloat = Constants.lineWidth
public var lineCap: CGLineCap = .round
public var circleColor: Color = Color(.primaryButtonBackground).opacity(Constants.backgroundOpacity)
public var fillColor: Color = Color(.primaryButtonBackground)

private let arcStart: Double = Constants.initialArcStart
private let animationDuration: Double = 1.6

@State private var arcEnd: Double = Constants.initialArcEnd
@State private var rotation: Angle = Constants.threeQuarterRotation
@State private var viewRotation: Angle = .radians(0)
@State private var arcTimer: Timer?

public init(size: CGFloat, lineWidth: CGFloat = Constants.lineWidth, lineCap: CGLineCap = .round, circleColor: Color? = nil, fillColor: Color? = nil) {
self.size = size
self.lineWidth = lineWidth
self.lineCap = lineCap
self.circleColor = circleColor ?? Color(.primaryButtonBackground).opacity(Constants.backgroundOpacity)
self.fillColor = fillColor ?? Color(.primaryButtonBackground)
}

public func makeBody(configuration: ProgressViewStyleConfiguration) -> some View {
VStack {
ZStack {
Expand Down Expand Up @@ -78,21 +85,21 @@ public struct IndefiniteCircularProgressViewStyle: ProgressViewStyle {
}
}

private extension IndefiniteCircularProgressViewStyle {
public extension IndefiniteCircularProgressViewStyle {
enum Constants {
static let lineWidth: CGFloat = 10.0
static let backgroundOpacity: CGFloat = 0.2
public static let lineWidth: CGFloat = 10.0
public static let backgroundOpacity: CGFloat = 0.2

static let initialArcStart: Double = 0
static let initialArcEnd: Double = 0.05
static let fullCircle: Double = 1
public static let initialArcStart: Double = 0
public static let initialArcEnd: Double = 0.05
public static let fullCircle: Double = 1

static let threeQuarterRotation: Angle = .radians((9 * Double.pi)/6)
static let fullRotation: Angle = .radians(Double.pi * 2)
public static let threeQuarterRotation: Angle = .radians((9 * Double.pi)/6)
public static let fullRotation: Angle = .radians(Double.pi * 2)
}

enum Localization {
static let inProgressAccessibilityLabel = NSLocalizedString(
public static let inProgressAccessibilityLabel = NSLocalizedString(
"In progress",
comment: "Accessibility label for an indeterminate loading indicator")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ import SwiftUI
import Combine

@Observable
final class KeyboardObserver {
private(set) var isKeyboardVisible: Bool = false
private(set) var keyboardHeight: CGFloat = 0
public final class KeyboardObserver {
public private(set) var isKeyboardVisible: Bool = false
public private(set) var keyboardHeight: CGFloat = 0

/// When an external keyboard is in use, iPadOS shows a quicktype bar at the bottom of the screen.
/// This is reported as a keyboard with height, so `isKeyboardVisible` will be true and
/// keyboard height will be > 0.
/// However, it's much less of an impingement on the view, so there may be no modification to the view required.
/// `isFullSizeKeyboardVisible` is true when the full software keyboard is shown.
var isFullSizeKeyboardVisible: Bool {
public var isFullSizeKeyboardVisible: Bool {
return keyboardHeight > Constants.hardwareKeyboardHelperBarHeightThreshold
}

private var cancellables = Set<AnyCancellable>()

init() {
public init() {
NotificationCenter.Publisher(center: .default, name: UIResponder.keyboardWillShowNotification)
.merge(with: NotificationCenter.Publisher(center: .default, name: UIResponder.keyboardDidShowNotification))
.receive(on: DispatchQueue.main)
Expand Down Expand Up @@ -47,9 +47,9 @@ final class KeyboardObserver {
}
}

private extension KeyboardObserver {
public extension KeyboardObserver {
enum Constants {
static let hardwareKeyboardHelperBarHeightThreshold: CGFloat = 90
public static let hardwareKeyboardHelperBarHeightThreshold: CGFloat = 90
}
}

Expand All @@ -60,22 +60,22 @@ private struct KeyboardObserverKey: EnvironmentKey {
}
}

extension EnvironmentValues {
public extension EnvironmentValues {
var keyboardObserver: KeyboardObserver {
get { self[KeyboardObserverKey.self] }
set { self[KeyboardObserverKey.self] = newValue }
}
}

struct KeyboardObserverProvider: ViewModifier {
public struct KeyboardObserverProvider: ViewModifier {
@State private var observer = KeyboardObserver()

func body(content: Content) -> some View {
public func body(content: Content) -> some View {
content.environment(\.keyboardObserver, observer)
}
}

extension View {
public extension View {
func injectKeyboardObserver() -> some View {
modifier(KeyboardObserverProvider())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import SwiftUI

/// Wraps a VStack inside a ScrollView, ensuring the content expands to fill the available space
///
struct ScrollableVStack<Content: View>: View {
public struct ScrollableVStack<Content: View>: View {
let alignment: HorizontalAlignment
let padding: CGFloat
let spacing: CGFloat?
let content: Content

init(
public init(
alignment: HorizontalAlignment = .center,
padding: CGFloat = 24,
spacing: CGFloat? = nil,
Expand All @@ -20,7 +20,7 @@ struct ScrollableVStack<Content: View>: View {
self.content = content()
}

var body: some View {
public var body: some View {
GeometryReader { geometry in
ScrollView {
VStack(alignment: alignment, spacing: spacing) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SwiftUI

/// Text field has a rounded border that has a thicker border and brighter border color when the field is focused.
struct WooRoundedBorderTextFieldStyle: TextFieldStyle {
public struct WooRoundedBorderTextFieldStyle: TextFieldStyle {
private let focused: Bool
private let focusedBorderColor: Color
private let unfocusedBorderColor: Color
Expand All @@ -19,7 +19,7 @@ struct WooRoundedBorderTextFieldStyle: TextFieldStyle {
/// - insets: The insets between the background border and the text input.
/// - height: An optional fixed height for the field.
/// - content: Optional closure to wrap the text field content.
init(focused: Bool,
public init(focused: Bool,
focusedBorderColor: Color = Defaults.focusedBorderColor,
unfocusedBorderColor: Color = Defaults.unfocusedBorderColor,
backgroundColor: Color = .clear,
Expand All @@ -37,7 +37,7 @@ struct WooRoundedBorderTextFieldStyle: TextFieldStyle {
self.content = content
}

func _body(configuration: TextField<Self._Label>) -> some View {
public func _body(configuration: TextField<Self._Label>) -> some View {
let styledContent = content?(configuration) ?? AnyView(configuration)

styledContent
Expand All @@ -53,11 +53,11 @@ struct WooRoundedBorderTextFieldStyle: TextFieldStyle {
}
}

extension WooRoundedBorderTextFieldStyle {
public extension WooRoundedBorderTextFieldStyle {
enum Defaults {
static let focusedBorderColor: Color = .init(uiColor: .brand)
static let unfocusedBorderColor: Color = .gray
static let insets = EdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
public static let focusedBorderColor: Color = .init(uiColor: .brand)
public static let unfocusedBorderColor: Color = .gray
public static let insets = EdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Combine

/// Interface for the observing connectivity
///
protocol ConnectivityObserver {
public protocol ConnectivityObserver {
/// Getter for current state of the connectivity.
var currentStatus: ConnectivityStatus { get }

Expand All @@ -21,7 +21,7 @@ protocol ConnectivityObserver {
/// - unknown: It is unknown whether the network is reachable.
/// - notReachable: The network is not reachable.
/// - reachable: The network is reachable.
enum ConnectivityStatus: Equatable {
public enum ConnectivityStatus: Equatable {
case unknown
case notReachable
case reachable(type: ConnectionType)
Expand All @@ -32,7 +32,7 @@ enum ConnectivityStatus: Equatable {
/// - ethernetOrWiFi: The connection type is either over Ethernet or WiFi.
/// - cellular: The connection type is a cellular connection.
/// - other: The connection type is via a local loopback network, virtual network or other unknown types.
enum ConnectionType: Equatable {
public enum ConnectionType: Equatable {
case ethernetOrWiFi
case cellular
case other
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import Combine
import Network

final class DefaultConnectivityObserver: ConnectivityObserver {
public final class DefaultConnectivityObserver: ConnectivityObserver {

/// Network monitor to evaluate connection.
///
private let networkMonitor: NetworkMonitoring
private let observingQueue: DispatchQueue = .global(qos: .background)

@Published private(set) var currentStatus: ConnectivityStatus = .unknown
@Published private(set) public var currentStatus: ConnectivityStatus = .unknown

var statusPublisher: AnyPublisher<ConnectivityStatus, Never> {
public var statusPublisher: AnyPublisher<ConnectivityStatus, Never> {
$currentStatus.eraseToAnyPublisher()
}

public convenience init() {
self.init(networkMonitor: NWPathMonitor())
}

init(networkMonitor: NetworkMonitoring = NWPathMonitor()) {
self.networkMonitor = networkMonitor
startObserving()
Expand All @@ -25,11 +29,11 @@ final class DefaultConnectivityObserver: ConnectivityObserver {
}
}

func startObserving() {
public func startObserving() {
networkMonitor.start(queue: observingQueue)
}

func stopObserving() {
public func stopObserving() {
networkMonitor.cancel()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import SwiftUI

/// Autofocus for `TextField` and `TextEditor` in iOS 15 and later
///
struct AutofocusTextModifier: ViewModifier {
public struct AutofocusTextModifier: ViewModifier {

@FocusState private var textFieldIsFocused: Bool

func body(content: Content) -> some View {
public init() {}

public func body(content: Content) -> some View {
content
.focused($textFieldIsFocused)
.onAppear {
Expand All @@ -21,7 +23,7 @@ struct AutofocusTextModifier: ViewModifier {

// MARK: View extension

extension View {
public extension View {

/// Autofocus in `TextField` and `TextEditor` is available only for iOS15+
///
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import SwiftUI

extension View {
public extension View {
/// Renders a view if the provided `condition` is met.
/// If the `condition` is not met, an `nil` will be used in place of the receiver view.
///
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import SwiftUI

extension View {
public extension View {
/// Measures the height of a view and calls the provided callback with the height value.
/// The callback is called both when the view first appears and whenever its height changes.
/// If the view contains a list, consider wrapping it in a VStack to ensure the height updates are emitted as a group
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import SwiftUI

/// Custom view modifier for applying a rounded border to a view.
struct RoundedBorder: ViewModifier {
public struct RoundedBorder: ViewModifier {
let cornerRadius: CGFloat
let lineColor: Color
let lineWidth: CGFloat
let dashed: Bool

func body(content: Content) -> some View {
public init(cornerRadius: CGFloat, lineColor: Color, lineWidth: CGFloat, dashed: Bool) {
self.cornerRadius = cornerRadius
self.lineColor = lineColor
self.lineWidth = lineWidth
self.dashed = dashed
}

public func body(content: Content) -> some View {
content
.overlay {
RoundedRectangle(cornerRadius: cornerRadius)
Expand All @@ -19,12 +26,11 @@ struct RoundedBorder: ViewModifier {

private extension RoundedBorder {
enum Layout {
static let height: CGFloat = 1
static let dashLength: CGFloat = 5
}
}

extension View {
public extension View {
/// Applies a rounded border to a view.
func roundedBorder(cornerRadius: CGFloat, lineColor: Color, lineWidth: CGFloat, dashed: Bool = false) -> some View {
self.modifier(RoundedBorder(cornerRadius: cornerRadius, lineColor: lineColor, lineWidth: lineWidth, dashed: dashed))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import SwiftUI

/// Preference key for communicating sizes
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize? = nil
public struct SizePreferenceKey: PreferenceKey {
public static var defaultValue: CGSize? = nil

static func reduce(value: inout CGSize?, nextValue: () -> CGSize?) {
public static func reduce(value: inout CGSize?, nextValue: () -> CGSize?) {
// Take the response of the first child which updates the key. Disallow further updates from its children.
value = value ?? nextValue()
}
}

/// View modifier that conditionally wraps the `content` in a `ScrollView` if the `content` height exceeds the view height.
///
struct ConditionalVerticalScrollModifier: ViewModifier {
public struct ConditionalVerticalScrollModifier: ViewModifier {
/// Defines if the content should scroll or not.
@State private var shouldScroll: Bool = false

func body(content: Content) -> some View {
public func body(content: Content) -> some View {
GeometryReader { parentGeometry in
Group {
if shouldScroll {
Expand Down Expand Up @@ -52,7 +52,7 @@ struct ConditionalVerticalScrollModifier: ViewModifier {

// MARK: View Extensions

extension View {
public extension View {
/// Allows the view to scroll vertically when the content height is greater than its parent height.
///
func scrollVerticallyIfNeeded() -> some View {
Expand Down
Loading