chore: enabled cancel requests and clear input 703517bf
Steve · 2025-12-30 19:46 2 file(s) · +48 −12
Titan/Views/BrowserToolbar.swift +41 −12
22 22
    let onBack: () -> Void
23 23
    let onForward: () -> Void
24 24
    let onSubmitURL: () -> Void
25 +
    let onCancel: () -> Void
25 26
    let onDismissKeyboard: () -> Void
26 27
    let onShowTabs: () -> Void
27 28
    let onNewTab: () -> Void
92 93
    }
93 94
94 95
    private var urlTextField: some View {
95 -
        TextField("gemini:// or search", text: $urlText)
96 -
            .focused(isURLFocused)
97 -
            .autocapitalization(.none)
98 -
            .disableAutocorrection(true)
99 -
            .keyboardType(.webSearch)
100 -
            .submitLabel(.go)
101 -
            .onSubmit {
102 -
                isURLFocused.wrappedValue = false
103 -
                onSubmitURL()
96 +
        HStack(spacing: 0) {
97 +
            TextField("gemini:// or search", text: $urlText)
98 +
                .focused(isURLFocused)
99 +
                .autocapitalization(.none)
100 +
                .disableAutocorrection(true)
101 +
                .keyboardType(.webSearch)
102 +
                .submitLabel(.go)
103 +
                .onSubmit {
104 +
                    isURLFocused.wrappedValue = false
105 +
                    onSubmitURL()
106 +
                }
107 +
                .padding(.leading, 12)
108 +
                .padding(.vertical, 12)
109 +
110 +
            if isLoading {
111 +
                Button(action: onCancel) {
112 +
                    Image(systemName: "xmark.circle.fill")
113 +
                        .font(.body)
114 +
                        .foregroundStyle(themeSettings.toolbarButtonColor.opacity(0.7))
115 +
                }
116 +
                .padding(.horizontal, 10)
117 +
                .transition(.opacity.combined(with: .scale(scale: 0.8)))
118 +
            } else if isURLFocused.wrappedValue && !urlText.isEmpty {
119 +
                Button {
120 +
                    urlText = ""
121 +
                } label: {
122 +
                    Image(systemName: "xmark.circle.fill")
123 +
                        .font(.body)
124 +
                        .foregroundStyle(themeSettings.toolbarButtonColor.opacity(0.7))
125 +
                }
126 +
                .padding(.horizontal, 10)
127 +
                .transition(.opacity.combined(with: .scale(scale: 0.8)))
128 +
            } else {
129 +
                Spacer()
130 +
                    .frame(width: 12)
104 131
            }
105 -
            .padding(.horizontal, 12)
106 -
            .padding(.vertical, 12)
107 -
            .glassEffect(.regular, in: .capsule)
132 +
        }
133 +
        .glassEffect(.regular, in: .capsule)
134 +
        .animation(.easeInOut(duration: 0.2), value: isLoading)
135 +
        .animation(.easeInOut(duration: 0.2), value: isURLFocused.wrappedValue)
136 +
        .animation(.easeInOut(duration: 0.2), value: urlText.isEmpty)
108 137
    }
109 138
110 139
    private var dismissButton: some View {
Titan/Views/ContentView.swift +7 −0
95 95
                    onBack: goBack,
96 96
                    onForward: goForward,
97 97
                    onSubmitURL: { navigateTo(urlText) },
98 +
                    onCancel: cancelCurrentRequest,
98 99
                    onDismissKeyboard: { isURLFocused = false },
99 100
                    onShowTabs: { showTabs = true },
100 101
                    onNewTab: {
321 322
        historyIndex += 1
322 323
        urlText = history[historyIndex]
323 324
        fetchContent(addToHistory: false)
325 +
    }
326 +
327 +
    private func cancelCurrentRequest() {
328 +
        currentFetchTask?.cancel()
329 +
        currentFetchTask = nil
330 +
        isLoading = false
324 331
    }
325 332
326 333
    private func addToNavigationHistory(url: String) {