From 6273b2d917c66441c45b3017f42a524fcaeb7f36 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Fri, 31 Oct 2025 00:56:51 +0800 Subject: [PATCH] :lipstick: Auto hide input on watchOS --- .../Views/ChatViews.swift | 69 ++++++++++++------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/ios/WatchRunner Watch App/Views/ChatViews.swift b/ios/WatchRunner Watch App/Views/ChatViews.swift index 0f398e2f..997c9dc9 100644 --- a/ios/WatchRunner Watch App/Views/ChatViews.swift +++ b/ios/WatchRunner Watch App/Views/ChatViews.swift @@ -263,6 +263,8 @@ struct ChatRoomView: View { @State private var hasLoadedMessages = false // Track if messages have been loaded @State private var messageText = "" // Text input for sending messages @State private var isSending = false // Track sending state + @State private var isInputHidden = false // Track if input should be hidden during scrolling + @State private var scrollTimer: Timer? // Timer to show input after scrolling stops @State private var cancellables = Set() // For managing subscriptions @@ -311,6 +313,7 @@ struct ChatRoomView: View { } .padding(.horizontal) .padding(.vertical, 8) + .padding(.bottom, 8) } .onAppear { // Scroll to bottom when messages load @@ -326,37 +329,55 @@ struct ChatRoomView: View { } } } + .onScrollPhaseChange { _, phase in + switch phase { + case .interacting: + if !isInputHidden { + withAnimation(.easeOut(duration: 0.2)) { + isInputHidden = true + } + } + case .idle: + withAnimation(.easeIn(duration: 0.3)) { + isInputHidden = false + } + default: break + } + } } } // Message input area - HStack(spacing: 8) { - TextField("Send message...", text: $messageText) - .font(.system(size: 14)) - .disabled(isSending) - .frame(height: 40) + if !isInputHidden { + HStack(spacing: 8) { + TextField("Send message...", text: $messageText) + .font(.system(size: 14)) + .disabled(isSending) + .frame(height: 40) - Button { - Task { - await sendMessage() - } - } label: { - if isSending { - ProgressView() - .frame(width: 20, height: 20) - } else { - Image(systemName: "arrow.up.circle.fill") - .resizable() - .frame(width: 20, height: 20) + Button { + Task { + await sendMessage() + } + } label: { + if isSending { + ProgressView() + .frame(width: 20, height: 20) + } else { + Image(systemName: "arrow.up.circle.fill") + .resizable() + .frame(width: 20, height: 20) + } } + .labelStyle(.iconOnly) + .buttonStyle(.glass) + .disabled(messageText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || isSending) + .frame(width: 40, height: 40) } - .labelStyle(.iconOnly) - .buttonStyle(.glass) - .disabled(messageText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || isSending) - .frame(width: 40, height: 40) + .padding(.horizontal) + .padding(.top, 8) + .transition(.move(edge: .bottom).combined(with: .opacity)) } - .padding(.horizontal) - .padding(.top, 8) } .navigationTitle(room.name ?? "Chat") .task { @@ -368,6 +389,8 @@ struct ChatRoomView: View { .onDisappear { cancellables.forEach { $0.cancel() } cancellables.removeAll() + scrollTimer?.invalidate() + scrollTimer = nil } }