Bottom Tab Bar Visibility Adjustment
Nucleic-Session: 747527BF-AEE9-4939-BE70-A14F1F3BBBA8 Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
@@ -144,6 +144,10 @@ struct NewChatAffordance: ViewModifier {
|
||||
var project: WireProject? = nil
|
||||
/// Owned by the caller so it can also open the composer programmatically (iPad ⌘N on Home).
|
||||
@Binding var isPresented: Bool
|
||||
/// Prompt text and its focus live here so the scrim tap and auto-focus can coordinate with the
|
||||
/// composer (whether it's empty, whether the keyboard is up).
|
||||
@State private var draft = ""
|
||||
@FocusState private var draftFocused: Bool
|
||||
|
||||
/// The button only makes sense when this device can control a Mac and there's a project to
|
||||
/// start a chat in; otherwise the composer it opens would be inert.
|
||||
@@ -151,6 +155,8 @@ struct NewChatAffordance: ViewModifier {
|
||||
store.canControl && (project != nil || !store.dashboard.projects.isEmpty)
|
||||
}
|
||||
|
||||
private var isEmpty: Bool { draft.trimmingCharacters(in: .whitespaces).isEmpty }
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
// The "+" disc — hidden while the composer is up so it doesn't sit over the bar.
|
||||
@@ -175,7 +181,7 @@ struct NewChatAffordance: ViewModifier {
|
||||
}
|
||||
}
|
||||
// The composer itself, floating up from the bottom over a light scrim — no modal pane,
|
||||
// no nav chrome, just the entry box. Tapping the scrim dismisses it.
|
||||
// no nav chrome, just the entry box.
|
||||
.overlay {
|
||||
if isPresented {
|
||||
ZStack(alignment: .bottom) {
|
||||
@@ -183,8 +189,14 @@ struct NewChatAffordance: ViewModifier {
|
||||
.fill(.black.opacity(0.2))
|
||||
.ignoresSafeArea()
|
||||
.transition(.opacity)
|
||||
.onTapGesture { isPresented = false }
|
||||
StartChatComposer(onStart: { isPresented = false }, lockedProject: project)
|
||||
// Tapping away drops the keyboard; with nothing typed there's nothing to
|
||||
// keep the bar around for, so close it. A draft in progress stays open
|
||||
// (keyboard down) so a stray tap doesn't discard it.
|
||||
.onTapGesture {
|
||||
if isEmpty { isPresented = false } else { draftFocused = false }
|
||||
}
|
||||
StartChatComposer(draft: $draft, focus: $draftFocused,
|
||||
onStart: { isPresented = false }, lockedProject: project)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.bottom, 8)
|
||||
.transition(.move(edge: .bottom).combined(with: .opacity))
|
||||
@@ -192,6 +204,20 @@ struct NewChatAffordance: ViewModifier {
|
||||
}
|
||||
}
|
||||
.animation(.spring(response: 0.35, dampingFraction: 0.86), value: isPresented)
|
||||
.onChange(of: isPresented) { _, open in
|
||||
if open {
|
||||
draft = ""
|
||||
// Focus once the bar has sprung into place, so the keyboard rises against a
|
||||
// settled layout — otherwise its avoidance inset is computed mid-animation and
|
||||
// the keyboard lands overlapping the bar until the next re-layout.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
|
||||
if isPresented { draftFocused = true }
|
||||
}
|
||||
} else {
|
||||
draftFocused = false
|
||||
draft = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user