fix: route the URL shortcut to the inline input
This commit is contained in:
@@ -79,6 +79,13 @@ private enum WindowDragCheck {
|
||||
}
|
||||
|
||||
static func clickStartURL(in window: NSWindow) {
|
||||
if phase != 0 {
|
||||
let event = NSEvent.keyEvent(with: .keyDown, location: .zero, modifierFlags: [.command, .shift],
|
||||
timestamp: ProcessInfo.processInfo.systemUptime, windowNumber: window.windowNumber,
|
||||
context: nil, characters: "O", charactersIgnoringModifiers: "o", isARepeat: false, keyCode: 31)!
|
||||
NSApp.postEvent(event, atStart: false)
|
||||
return
|
||||
}
|
||||
for type in [NSEvent.EventType.leftMouseDown, .leftMouseUp] {
|
||||
let event = NSEvent.mouseEvent(with: type, location: NSPoint(x: 400, y: 272),
|
||||
modifierFlags: [], timestamp: ProcessInfo.processInfo.systemUptime,
|
||||
|
||||
@@ -41,7 +41,7 @@ The start screen uses a fixed 640 × 400-point two-pane window: Terebi's identit
|
||||
|
||||
Start-screen actions use 14-point text and begin 64 points below the top edge. Branding uses a 16-point app name and 12-point version; the drop hint uses 13-point text. Open actions have no idle fill; their background appears on hover or press.
|
||||
|
||||
URL-field expansion and collapse use a 250 ms ease-in/out fade with a subtle top-anchored scale; recent rows move with the transition without resizing the window. Reduce Motion makes the change immediate. Hiding or rapidly toggling the field preserves its draft, and hiding releases keyboard focus.
|
||||
URL-field expansion and collapse use a 200 ms ease-in/out fade with a subtle top-anchored scale; recent rows move with the transition without resizing the window. Reduce Motion makes the change immediate. The Open URL button and ⇧⌘O toggle the same inline input, retaining its draft and releasing keyboard focus when hidden. During playback, the input appears over the player without interrupting playback; no separate URL dialog opens.
|
||||
|
||||
| Action | Default shortcut |
|
||||
| --- | --- |
|
||||
|
||||
@@ -94,6 +94,9 @@ extension PlayerModel {
|
||||
|
||||
private func handleKeyEvent(_ event: NSEvent, in window: NSWindow, chord: KeyChord) -> Bool {
|
||||
guard event.window === window, NSApp.modalWindow == nil, window.attachedSheet == nil else { return false }
|
||||
if chord.modifiers.contains(.command), keyBindings.shortcuts(for: .openYoutube).contains(chord) {
|
||||
return perform(.openYoutube)
|
||||
}
|
||||
let responder = window.firstResponder
|
||||
if let text = responder as? NSTextView, text.isEditable || text.isSelectable { return false }
|
||||
if let text = responder as? NSTextField, text.isEditable || text.isSelectable { return false }
|
||||
|
||||
+17
-23
@@ -29,6 +29,7 @@ final class PlayerModel: ObservableObject {
|
||||
|
||||
@Published private(set) var state = PlayerState()
|
||||
@Published private(set) var fileName: String?
|
||||
@Published var showsYouTubeInput = false
|
||||
@Published private(set) var fileIcon: NSImage?
|
||||
@Published private(set) var commandError: String?
|
||||
@Published private(set) var queue = PlaybackQueue()
|
||||
@@ -292,23 +293,6 @@ final class PlayerModel: ObservableObject {
|
||||
if append { addToQueue(panel.urls) } else { openFiles(panel.urls) }
|
||||
}
|
||||
|
||||
func openYouTubePanel() {
|
||||
guard canOpen else { return }
|
||||
defer { window?.makeFirstResponder(nil) }
|
||||
revealControls()
|
||||
let alert = NSAlert()
|
||||
alert.messageText = "Open YouTube Video"
|
||||
alert.informativeText = "Paste a YouTube video URL."
|
||||
alert.addButton(withTitle: "Open")
|
||||
alert.addButton(withTitle: "Cancel")
|
||||
let field = NSTextField(frame: NSRect(x: 0, y: 0, width: 360, height: 24))
|
||||
field.placeholderString = "https://www.youtube.com/watch?v=…"
|
||||
field.setAccessibilityLabel("YouTube video URL")
|
||||
alert.accessoryView = field
|
||||
alert.window.initialFirstResponder = field
|
||||
guard alert.runModal() == .alertFirstButtonReturn else { return }
|
||||
openYouTube(field.stringValue)
|
||||
}
|
||||
|
||||
func openYouTube(_ text: String) {
|
||||
guard canOpen else { return }
|
||||
@@ -320,6 +304,7 @@ final class PlayerModel: ObservableObject {
|
||||
revealControls()
|
||||
return
|
||||
}
|
||||
showsYouTubeInput = false
|
||||
clearQueue()
|
||||
resolveYouTube(url, height: nil)
|
||||
}
|
||||
@@ -963,7 +948,7 @@ final class PlayerModel: ObservableObject {
|
||||
window?.level = isOnTop ? .floating : .normal
|
||||
revealControls()
|
||||
case .openFile: openPanel()
|
||||
case .openYoutube: openYouTubePanel()
|
||||
case .openYoutube: showsYouTubeInput.toggle()
|
||||
case .closeFile: closeFile()
|
||||
case .quit: NSApp.terminate(nil)
|
||||
case .showBufferInfo: setShowsBufferInfo(true)
|
||||
@@ -2094,7 +2079,7 @@ private struct PlayerContent: View {
|
||||
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
||||
@ViewState private var showsRemainingTime = false
|
||||
@ViewState private var dropTargeted = false
|
||||
@ViewState private var showsYouTubeInput = false
|
||||
private var showsYouTubeInput: Bool { model.showsYouTubeInput }
|
||||
@ViewState private var youTubeURL = ""
|
||||
@FocusState private var youTubeInputFocused: Bool
|
||||
@ViewState private var controlSize = CGSize(width: 440, height: 68)
|
||||
@@ -2133,9 +2118,7 @@ private struct PlayerContent: View {
|
||||
}
|
||||
|
||||
private func toggleYouTubeInput() {
|
||||
if showsYouTubeInput { youTubeInputFocused = false }
|
||||
showsYouTubeInput.toggle()
|
||||
if showsYouTubeInput { youTubeInputFocused = true }
|
||||
model.perform(.openYoutube)
|
||||
}
|
||||
|
||||
private func startScreen(in size: CGSize) -> some View {
|
||||
@@ -2227,7 +2210,7 @@ private struct PlayerContent: View {
|
||||
.padding(.top, 20)
|
||||
}
|
||||
}
|
||||
.animation(reduceMotion ? nil : .easeInOut(duration: 0.25), value: showsYouTubeInput)
|
||||
.animation(reduceMotion ? nil : .easeInOut(duration: 0.2), value: showsYouTubeInput)
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.disabled(!model.canOpen)
|
||||
.padding(.horizontal, size.width < 600 ? 14 : 30)
|
||||
@@ -2808,6 +2791,17 @@ private struct PlayerContent: View {
|
||||
.tint(Color(SunsetPalette.accent))
|
||||
.background(WindowChrome(model: model))
|
||||
.onChange(of: windowDragging) { _, active in model.setControlsDragging(active) }
|
||||
.onChange(of: showsYouTubeInput) { _, shown in youTubeInputFocused = shown }
|
||||
.overlay(alignment: .top) {
|
||||
if model.fileName != nil && showsYouTubeInput {
|
||||
startURLInput
|
||||
.padding(12)
|
||||
.background(PlayerGlass().allowsHitTesting(false))
|
||||
.frame(maxWidth: 420)
|
||||
.padding(.top, 44)
|
||||
.transition(.opacity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var windowDragBackground: some View {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
- scoped native background dragging across start/playback/queue/error/Cast/compact views, with passive loading/audio overlays passing input through; 20 native input-routing probes passed, including controls and row-reorder exclusions; physical pointer dragging and Cast-screen interaction still need manual verification
|
||||
- [ ] on the start screen:
|
||||
- [x] make the youtube url input field that appears when clicking the youtube button appear with a nice transition
|
||||
- 250 ms fade/scale with animated row reflow; native focus, draft-preservation and rapid-reversal checks passed, including an isolated Reduce Motion branch smoke check; animation feel still needs manual verification
|
||||
- 200 ms fade/scale with animated row reflow; the button and ⇧⌘O toggle the same inline input, including while editing; native focus, draft-preservation and rapid-reversal checks cover mouse/shortcut interoperation
|
||||
- [ ] change the youtube button to general streaming
|
||||
- we can figure out the stream and how to handle it from the url (i.e. if youtube url, handle as youtube stream; if miruro url, handle accordingly)
|
||||
- [ ] check whether we're using appropriately new apple ui APIs / SDKs for the project.
|
||||
- we should strive to use modern and idiomatic SDKs and APIs including SwiftUI among others
|
||||
Reference in New Issue
Block a user