I want to execute an action when the button press begins and then when the button stops being pressed. I was looking for a simple solution, but got into more complicated configurations. One option that is pretty simple and close is the one I got from BlueSpud. The button action is not used so I tried:
    struct MyView: View {
    @State private var pressing = false
    var body: some View {
        Text("Button")
            .background(self.pressing ? Color.red : Color.blue)
            .gesture(DragGesture(minimumDistance: 0.0)
                .onChanged { _ in
                    self.pressing = true
                    print("Pressing started and/or ongoing")
            }
            .onEnded { _ in
                self.pressing = false
                print("Pressing ended")
            })
    }
}
The problem with this code is that if you drag your finger out of the button area while pressing, .onEnded never gets called, and without a reliable end to the event, the solution doesn't work.
I have also tried Apple's example for composing SwiftUI gestures. It provides a very consistent control over the pressed and unpressed states, but I can't seem to know where to insert my actions:
struct PressedButton: View {
    var startAction: ()->Void
    var endAction: ()->Void
    enum DragState {
        case inactive
        case pressing
        case dragging(translation: CGSize)
        var translation: CGSize {
            switch self {
            case .inactive, .pressing:
                return .zero
            case .dragging(let translation):
                return translation
            }
        }
        var isActive: Bool {
            switch self {
            case .inactive:
                print("DragState inactive but I can't add my action here")
                //self.endAction()
                return false
            case .pressing, .dragging:
                return true
            }
        }
        var isDragging: Bool {
            switch self {
            case .inactive, .pressing:
                return false
            case .dragging:
                return true
            }
        }
    }
    @GestureState var dragState = DragState.inactive
    var body: some View {
        let longPressDrag = LongPressGesture(minimumDuration: 0.1)
        .sequenced(before: DragGesture())
        .updating($dragState) { value, state, transaction in
            switch value {
            // Long press begins.
            case .first(true):
                print("Long press begins. I can add my action here")
                self.startAction()
                state = .pressing
            // Long press confirmed, dragging may begin.
            case .second(true, let drag):
                //print("Long press dragging")
                state = .dragging(translation: drag?.translation ?? .zero)
             // Dragging ended or the long press cancelled.
            default:
                print("Long press inactive but it doesn't get called")
                state = .inactive
            }
        }
        .onEnded { _ in
            print("Long press ended but it doesn't get called")
            }
        return Text("Button")
            .background(dragState.isActive ? Color.purple : Color.orange)
            .gesture(longPressDrag)
    }
}