Skip to content

Commit

Permalink
TimecodeField: Added Return and Escape keypress action view modifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
orchetect committed Oct 13, 2024
1 parent 57ded74 commit 53d4a32
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ extension TimecodeField {
@Environment(\.timecodeHighlightStyle) private var timecodeHighlightStyle: Color?
@Environment(\.timecodeSeparatorStyle) private var timecodeSeparatorStyle: Color?
@Environment(\.timecodeValidationStyle) private var timecodeValidationStyle: Color?
@Environment(\.timecodeFieldReturnAction) private var timecodeFieldReturnAction: TimecodeField.FieldAction?
@Environment(\.timecodeFieldEscapeAction) private var timecodeFieldEscapeAction: TimecodeField.FieldAction?

// MARK: - Internal State

Expand Down Expand Up @@ -240,17 +242,33 @@ extension TimecodeField {
return .handled

case .escape:
endEditing()
return .handled
perform(fieldAction: timecodeFieldEscapeAction)
// pass through to any receivers that accept cancel action
return .ignored

case .return:
endEditing()
return .ignored // pass through to any buttons that may have default action
perform(fieldAction: timecodeFieldReturnAction)
// pass through to any receivers that accept default action
return .ignored

default:
return .ignored
}
}

private func perform(fieldAction: TimecodeField.FieldAction?) {
// a `nil` action does nothing.
guard let fieldAction else { return }

switch fieldAction {
case .endEditing:
endEditing()
case let .resetComponentFocus(component):
let component = component ??
Timecode.Component.first(excluding: invisibleComponents)
componentEditing = component
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,55 @@
import SwiftUI
import TimecodeKit

// MARK: - TimecodeFieldReturnAction

/// Sets the `Return` key action for ``TimecodeField`` views.
@_documentation(visibility: internal)
@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
struct TimecodeFieldReturnActionKey: EnvironmentKey {
public static var defaultValue: TimecodeField.FieldAction? = nil
}

@_documentation(visibility: internal)
@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
extension EnvironmentValues {
/// Sets the `Return` key action for ``TimecodeField`` views.
public var timecodeFieldReturnAction: TimecodeField.FieldAction? {
get { self[TimecodeFieldReturnActionKey.self] }
set { self[TimecodeFieldReturnActionKey.self] = newValue }
}
}

// MARK: - TimecodeFieldEscapeAction

/// Sets the `Escape` key action for ``TimecodeField`` views.
@_documentation(visibility: internal)
@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
struct TimecodeFieldEscapeActionKey: EnvironmentKey {
public static var defaultValue: TimecodeField.FieldAction? = nil
}

@_documentation(visibility: internal)
@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
extension EnvironmentValues {
/// Sets the `Escape` key action for ``TimecodeField`` views.
public var timecodeFieldEscapeAction: TimecodeField.FieldAction? {
get { self[TimecodeFieldEscapeActionKey.self] }
set { self[TimecodeFieldEscapeActionKey.self] = newValue }
}
}

// MARK: - TimecodeFormat

/// Sets the timecode string format for ``TimecodeField`` and ``Text(timecode:)`` views.
/// Sets the timecode string format for ``TimecodeField`` and ``TimecodeText`` views.
@_documentation(visibility: internal)
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
struct TimecodeFormatKey: EnvironmentKey {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// TimecodeField Types.swift
// TimecodeKit • https://github.com/orchetect/TimecodeKit
// © 2020-2024 Steffan Andrews • Licensed under MIT License
//

#if canImport(SwiftUI) && (os(macOS) || os(iOS) || os(visionOS))

import SwiftUI
import TimecodeKit

@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
extension TimecodeField {
/// An enum describing actions to perform in response to ``TimecodeField`` user input.
public enum FieldAction: Equatable, Hashable, Sendable {
/// End editing.
/// Removes focus from the timecode field.
case endEditing

/// Resets component focus to the specified component.
/// If `nil`, focus is reset to the first visible component.
case resetComponentFocus(component: Timecode.Component? = nil)
}
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,61 @@
import SwiftUI
import TimecodeKit

// MARK: - TimecodeFieldReturnAction

/// Sets the `Return` key action for ``TimecodeField`` views.
@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
struct TimecodeFieldReturnActionViewModifier: ViewModifier {
let format: TimecodeField.FieldAction?

func body(content: Content) -> some View {
content.environment(\.timecodeFieldReturnAction, format)
}
}

@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
extension View {
/// Sets the `Return` key action for ``TimecodeField`` views.
public func timecodeFieldReturnAction(
_ format: TimecodeField.FieldAction?
) -> some View {
modifier(TimecodeFieldReturnActionViewModifier(format: format))
}
}

// MARK: - TimecodeFieldEscapeAction

/// Sets the `Escape` key action for ``TimecodeField`` views.
@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
struct TimecodeFieldEscapeActionViewModifier: ViewModifier {
let format: TimecodeField.FieldAction?

func body(content: Content) -> some View {
content.environment(\.timecodeFieldEscapeAction, format)
}
}

@available(macOS 14, iOS 17, *)
@available(watchOS, unavailable)
@available(tvOS, unavailable)
extension View {
/// Sets the `Escape` key action for ``TimecodeField`` views.
public func timecodeFieldEscapeAction(
_ format: TimecodeField.FieldAction?
) -> some View {
modifier(TimecodeFieldEscapeActionViewModifier(format: format))
}
}

// MARK: - TimecodeFormat

/// Sets the timecode string format for ``TimecodeField`` and ``TimecodeText`` views.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
struct TimecodeFormatViewModifier: ViewModifier {
let format: Timecode.StringFormat
Expand All @@ -32,6 +85,8 @@ extension View {

// MARK: - TimecodeHighlightStyle

/// Sets the component highlight style for ``TimecodeField`` views.
/// By default, the application's `accentColor` is used.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
struct TimecodeHighlightStyleViewModifier: ViewModifier {
let color: Color?
Expand All @@ -54,6 +109,11 @@ extension View {

// MARK: - TimecodeSeparatorStyle

/// Sets the text separator style for ``TimecodeField`` and ``TimecodeText`` views.
/// If `color` is nil, the foreground style is used.
///
/// - Note: To set the default color of the component values, use `foregroundColor` or `foregroundStyle` view
/// modifiers.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
struct TimecodeSeparatorStyleViewModifier: ViewModifier {
let color: Color?
Expand All @@ -79,6 +139,12 @@ extension View {

// MARK: - TimecodeValidationStyle

/// Sets timecode component validation style for ``TimecodeField`` and ``TimecodeText`` views.
///
/// This foreground color will be used only for any timecode component values that are invalid for the given
/// properties (frame rate, subframes base, and upper limit).
///
/// If `nil`, validation is disabled and invalid components will not be colorized.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
struct TimecodeValidationStyleViewModifier: ViewModifier {
let color: Color?
Expand Down

0 comments on commit 53d4a32

Please sign in to comment.