ios: share prompt field across chat and agent views
TestFlight / Build and upload (push) Successful in 1m44s
TestFlight / Build and upload (push) Successful in 1m44s
This commit is contained in:
@@ -194,31 +194,31 @@ struct SybilAgentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var canSendComposer: Bool {
|
||||||
|
!room.composer.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && room.composer.utf16.count <= 40_000
|
||||||
|
}
|
||||||
|
|
||||||
private var composer: some View {
|
private var composer: some View {
|
||||||
HStack(alignment: .bottom, spacing: 10) {
|
HStack(alignment: .bottom, spacing: 10) {
|
||||||
TextField("Message Sybil…", text: $room.composer, axis: .vertical)
|
SybilPromptField(
|
||||||
.lineLimit(1...6)
|
text: $room.composer,
|
||||||
.font(.sybil(.body))
|
focused: $composerFocused,
|
||||||
.focused($composerFocused)
|
submit: submitComposer
|
||||||
.accessibilityIdentifier("agent-composer")
|
)
|
||||||
Button {
|
.accessibilityIdentifier("agent-composer")
|
||||||
let content = room.composer
|
|
||||||
if room.send(content) { room.composer = ""; atLatest = true }
|
SybilPromptSendButton(canSend: canSendComposer, submit: submitComposer)
|
||||||
} label: {
|
|
||||||
Image(systemName: "arrow.up")
|
|
||||||
.font(.system(size: 17, weight: .semibold))
|
|
||||||
.foregroundStyle(.white)
|
|
||||||
.frame(width: 38, height: 38)
|
|
||||||
.background(SybilTheme.primaryGradient, in: Circle())
|
|
||||||
}
|
|
||||||
.disabled(room.composer.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || room.composer.utf16.count > 40_000)
|
|
||||||
.accessibilityLabel("Send message")
|
|
||||||
.accessibilityIdentifier("agent-send")
|
.accessibilityIdentifier("agent-send")
|
||||||
}
|
}
|
||||||
.padding(12)
|
.padding(.horizontal, 14)
|
||||||
.background(SybilTheme.surfaceStrong, in: RoundedRectangle(cornerRadius: 22))
|
.padding(.bottom, 12)
|
||||||
.overlay(RoundedRectangle(cornerRadius: 22).stroke(SybilTheme.border))
|
.padding(.top, 6)
|
||||||
.padding(.horizontal, 12).padding(.bottom, 10).padding(.top, 6)
|
}
|
||||||
|
|
||||||
|
private func submitComposer() {
|
||||||
|
guard canSendComposer, room.send(room.composer) else { return }
|
||||||
|
room.composer = ""
|
||||||
|
atLatest = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct SybilPromptField: View {
|
||||||
|
var placeholder: String = "Enter Prompt"
|
||||||
|
@Binding var text: String
|
||||||
|
@FocusState.Binding var focused: Bool
|
||||||
|
var selection: Binding<TextSelection?>? = nil
|
||||||
|
var axis: Axis = .vertical
|
||||||
|
var submit: () -> Void
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Group {
|
||||||
|
if let selection {
|
||||||
|
TextField(placeholder, text: $text, selection: selection, axis: axis)
|
||||||
|
} else {
|
||||||
|
TextField(placeholder, text: $text, axis: axis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focused($focused)
|
||||||
|
.font(.sybil(.body))
|
||||||
|
.textInputAutocapitalization(.sentences)
|
||||||
|
.autocorrectionDisabled(false)
|
||||||
|
.lineLimit(1 ... 6)
|
||||||
|
.submitLabel(.send)
|
||||||
|
.onSubmit(submit)
|
||||||
|
.submitOnMacReturn(submit)
|
||||||
|
.padding(.horizontal, 12)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
.background(
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.fill(SybilTheme.composerGradient)
|
||||||
|
.opacity(0.98)
|
||||||
|
)
|
||||||
|
.foregroundStyle(SybilTheme.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SybilPromptSendButton: View {
|
||||||
|
var systemImage: String = "arrow.up"
|
||||||
|
var canSend: Bool
|
||||||
|
var submit: () -> Void
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: submit) {
|
||||||
|
Image(systemName: systemImage)
|
||||||
|
.font(.system(size: 17, weight: .semibold))
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
.background(
|
||||||
|
Circle()
|
||||||
|
.fill(
|
||||||
|
canSend
|
||||||
|
? AnyShapeStyle(SybilTheme.primaryGradient)
|
||||||
|
: AnyShapeStyle(SybilTheme.surface)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.foregroundStyle(canSend ? SybilTheme.text : SybilTheme.textMuted)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.disabled(!canSend)
|
||||||
|
.accessibilityLabel("Send message")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -95,46 +95,19 @@ struct SybilQuickQuestionView: View {
|
|||||||
private var composer: some View {
|
private var composer: some View {
|
||||||
VStack(alignment: .leading, spacing: 10) {
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
HStack(alignment: .bottom, spacing: 10) {
|
HStack(alignment: .bottom, spacing: 10) {
|
||||||
TextField(
|
SybilPromptField(
|
||||||
"Ask anything...",
|
placeholder: "Ask anything...",
|
||||||
text: Binding(
|
text: Binding(
|
||||||
get: { viewModel.quickQuestionPrompt },
|
get: { viewModel.quickQuestionPrompt },
|
||||||
set: { viewModel.updateQuickQuestionPrompt($0) }
|
set: { viewModel.updateQuickQuestionPrompt($0) }
|
||||||
),
|
),
|
||||||
|
focused: $promptFocused,
|
||||||
selection: $promptSelection,
|
selection: $promptSelection,
|
||||||
axis: .horizontal
|
axis: .horizontal,
|
||||||
|
submit: submitQuestion
|
||||||
)
|
)
|
||||||
.focused($promptFocused)
|
|
||||||
.font(.body)
|
|
||||||
.textInputAutocapitalization(.sentences)
|
|
||||||
.autocorrectionDisabled(false)
|
|
||||||
.submitLabel(.send)
|
|
||||||
.onSubmit(submitQuestion)
|
|
||||||
.padding(.horizontal, 12)
|
|
||||||
.padding(.vertical, 10)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.fill(SybilTheme.composerGradient)
|
|
||||||
.opacity(0.98)
|
|
||||||
)
|
|
||||||
.foregroundStyle(SybilTheme.text)
|
|
||||||
|
|
||||||
Button(action: submitQuestion) {
|
SybilPromptSendButton(canSend: viewModel.canSendQuickQuestion, submit: submitQuestion)
|
||||||
Image(systemName: "arrow.up")
|
|
||||||
.font(.body.weight(.semibold))
|
|
||||||
.frame(width: 40, height: 40)
|
|
||||||
.background(
|
|
||||||
Circle()
|
|
||||||
.fill(
|
|
||||||
viewModel.canSendQuickQuestion
|
|
||||||
? AnyShapeStyle(SybilTheme.primaryGradient)
|
|
||||||
: AnyShapeStyle(SybilTheme.surfaceStrong.opacity(0.92))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.foregroundStyle(viewModel.canSendQuickQuestion ? SybilTheme.text : SybilTheme.textMuted)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
.disabled(!viewModel.canSendQuickQuestion)
|
|
||||||
.accessibilityLabel("Ask quick question")
|
.accessibilityLabel("Ask quick question")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -613,47 +613,19 @@ struct SybilWorkspaceView: View {
|
|||||||
.accessibilityLabel("Attach file")
|
.accessibilityLabel("Attach file")
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField(
|
SybilPromptField(
|
||||||
viewModel.isSearchMode ? "Search the web" : "Enter Prompt",
|
placeholder: viewModel.isSearchMode ? "Search the web" : "Enter Prompt",
|
||||||
text: $viewModel.composer,
|
text: $viewModel.composer,
|
||||||
axis: .vertical
|
focused: $composerFocused,
|
||||||
|
submit: submitComposer
|
||||||
)
|
)
|
||||||
.focused($composerFocused)
|
|
||||||
.textInputAutocapitalization(.sentences)
|
|
||||||
.autocorrectionDisabled(false)
|
|
||||||
.lineLimit(1 ... 6)
|
|
||||||
.submitLabel(.send)
|
|
||||||
.onSubmit {
|
|
||||||
submitComposer()
|
|
||||||
}
|
|
||||||
.submitOnMacReturn(submitComposer)
|
|
||||||
.padding(.horizontal, 12)
|
|
||||||
.padding(.vertical, 10)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.fill(SybilTheme.composerGradient)
|
|
||||||
.opacity(0.98)
|
|
||||||
)
|
|
||||||
.foregroundStyle(SybilTheme.text)
|
|
||||||
|
|
||||||
Button {
|
SybilPromptSendButton(
|
||||||
submitComposer()
|
systemImage: viewModel.isSearchMode ? "magnifyingglass" : "arrow.up",
|
||||||
} label: {
|
canSend: viewModel.canSendComposer,
|
||||||
Image(systemName: viewModel.isSearchMode ? "magnifyingglass" : "arrow.up")
|
submit: submitComposer
|
||||||
.font(.system(size: 17, weight: .semibold))
|
)
|
||||||
.frame(width: 40, height: 40)
|
.accessibilityLabel(viewModel.isSearchMode ? "Search" : "Send message")
|
||||||
.background(
|
|
||||||
Circle()
|
|
||||||
.fill(
|
|
||||||
viewModel.canSendComposer
|
|
||||||
? AnyShapeStyle(SybilTheme.primaryGradient)
|
|
||||||
: AnyShapeStyle(SybilTheme.surface)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.foregroundStyle(viewModel.canSendComposer ? SybilTheme.text : SybilTheme.textMuted)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
.disabled(!viewModel.canSendComposer)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 14)
|
.padding(.horizontal, 14)
|
||||||
|
|||||||
Reference in New Issue
Block a user