# Messaging UX Improvements Design

**Date:** 2025-11-13
**Status:** Approved
**Target:** ChatView messaging interface

## Overview

Comprehensive redesign of the messaging input experience to achieve Apple-quality UX standards. Addresses three core issues plus additional polish for professional-grade messaging interface.

## Problem Statement

Current messaging interface has UX issues that detract from the cozy, professional experience:

1. **Input field starts fully expanded** (~130px) instead of compact, wasting screen space
2. **No auto-scroll on keyboard appearance** - messages don't stay visible when typing
3. **No keyboard dismissal** - tapping blank areas doesn't hide keyboard
4. **Missing polish** - lacks smooth animations and micro-interactions expected in modern messaging apps

## Design Goals

- Input field starts compact (~40px single line) and grows naturally with content
- Automatic scroll to bottom when keyboard appears
- Tap message area to dismiss keyboard
- Smooth animations matching iOS native messaging feel
- Maintain existing cozy design aesthetic
- Zero impact on existing WebSocket message flow

## Architecture

### Component Structure

```
ChatView
├── ScrollView (messages)
│   ├── Message bubbles
│   └── Tap gesture (dismiss keyboard)
├── DynamicTextInput (new UIViewRepresentable)
    ├── UITextView (auto-sizing)
    ├── Send button
    └── Keyboard observers
```

### Technical Approach

**Replace ExpandableMessageInput** with new `DynamicTextInput` component using UITextView wrapped in UIViewRepresentable:

- **iOS 16.4+ `sizeThatFits()` method** for automatic height calculation
- **UITextView with `isScrollEnabled = false`** for content-based sizing
- **Coordinator pattern** for delegate callbacks and text binding
- **Modern SwiftUI layout integration** via sizeThatFits proposal system

**Why UITextView over TextEditor:**
- TextEditor doesn't respect intrinsic content size (fills available space)
- UITextView provides precise control over sizing behavior
- Professional apps (Messages, WhatsApp) use UITextView approach
- Native iOS text input behavior with proper placeholder support

## Detailed Design

### 1. DynamicTextInput Component

**File:** `lichunWebsocket/Features/Messaging/Components/DynamicTextInput.swift`

**Implementation:**

```swift
struct DynamicTextInput: UIViewRepresentable {
    @Binding var text: String
    let canSend: Bool
    let onSend: () -> Void

    // Use sizeThatFits for iOS 16+ dynamic height
    func sizeThatFits(_ proposal: ProposedViewSize,
                     uiView: UITextView,
                     context: Context) -> CGSize? {
        return uiView.sizeThatFits(CGSize(
            width: proposal.width ?? 300,
            height: .infinity
        ))
    }
}
```

**Sizing Behavior:**
- **Initial height:** 40px (single line + padding)
- **Line height:** ~22px per line
- **Max height:** 120px (then internal scroll)
- **Growth:** Smooth expansion as text wraps

**Styling:**
- Warm gradient background (matches existing cozy theme)
- 20px corner radius (soft, approachable)
- Focus state: Primary color border with subtle glow
- Unfocused: Light border with minimal shadow
- Disabled: 0.6 opacity

**Send Button:**
- Circular 44x44pt button with gradient fill
- Arrow.up SF Symbol
- Enabled: Primary -> Accent gradient
- Disabled: Gray, 0.9 scale
- Haptic feedback on tap (medium impact)

### 2. Keyboard Management

**In ChatView:**

```swift
@State private var keyboardHeight: CGFloat = 0
@FocusState private var inputFocused: Bool

// Observers:
UIResponder.keyboardWillShowNotification
UIResponder.keyboardWillHideNotification
```

**Auto-Scroll Behavior:**
1. **Keyboard appears:** Scroll to bottom with 0.25s easeOut animation
2. **New message arrives:** Scroll to bottom (existing behavior preserved)
3. **Input focused:** Scroll to bottom if already near bottom
4. **Message sent:** Maintain bottom position

**Keyboard Avoidance:**
- Add bottom padding to ScrollView equal to `keyboardHeight`
- Input stays fixed at screen bottom
- Messages slide up naturally with keyboard
- Animation matches iOS keyboard curve (0.25s easeOut)

### 3. Tap-to-Dismiss Gesture

**Implementation:**

```swift
ScrollView { ... }
    .background(
        Color.clear
            .contentShape(Rectangle())
            .onTapGesture {
                inputFocused = false
                hideKeyboard()
            }
    )
```

**Gesture Priority:**
- Message bubbles: Tap enabled (for future long-press features)
- Blank areas: Dismiss keyboard
- Scrolling: Preserve scroll gestures
- Text selection: Don't interfere with selection drag

**User Feedback:**
- Haptic feedback on dismiss (light impact)
- Smooth keyboard slide-down animation

### 4. Animation Enhancements

**Message Bubble Entry:**
```swift
// New messages appear with:
- Slide up (offset y: 20 -> 0)
- Fade in (opacity: 0 -> 1)
- Gentle bounce (.spring(response: 0.5, dampingFraction: 0.75))
- Staggered delay for multiple messages
```

**Send Button:**
```swift
// On send tap:
- Scale animation (1.0 -> 0.9 -> 1.0)
- Arrow rotation pulse
- Medium haptic feedback
- Disable during send (prevent double-tap)
```

**Input Field Focus States:**
```swift
// Unfocused -> Focused transition:
- Border color: Gray -> Primary (0.3s spring)
- Shadow: Subtle -> Soft glow (0.3s)
- Scale: 1.0 -> 1.01 (barely perceptible lift)
```

**Keyboard Transitions:**
```swift
// All keyboard animations:
- Duration: 0.25s
- Curve: .easeOut (matches iOS native)
- Content slides smoothly with keyboard frame
```

## State Management

**Existing Patterns Preserved:**
- `@EnvironmentObject var webSocketService` - Message sending/receiving
- Energy check before send (10 energy required)
- WebSocket message protocol unchanged
- ConversationObj and ConversationMessage models unchanged

**New State:**
- `@FocusState private var inputFocused` - Keyboard tracking
- `@State private var keyboardHeight` - Layout adjustment
- UITextView internal height managed by sizeThatFits()

## Files Modified

1. **New:** `lichunWebsocket/Features/Messaging/Components/DynamicTextInput.swift`
   - UIViewRepresentable wrapper for UITextView
   - ~200 lines

2. **Modified:** `lichunWebsocket/Features/Messaging/Views/ChatView.swift`
   - Replace ExpandableMessageInput with DynamicTextInput
   - Add keyboard observers
   - Add tap gesture for dismissal
   - Add keyboard height padding
   - ~50 lines changed

3. **Deprecated:** `lichunWebsocket/Features/Messaging/Components/ExpandableMessageInput.swift`
   - Keep file for reference but unused
   - Can be deleted after testing

## Success Metrics

**Functional:**
- Input starts at ~40px and grows to ~120px smoothly
- Messages auto-scroll to bottom when keyboard appears
- Tapping message area dismisses keyboard
- All animations feel smooth and intentional
- No regressions in message sending/receiving

**Qualitative:**
- Feels like native iOS Messages app
- Matches app's cozy design aesthetic
- Users don't notice the input - it "just works"
- Zero cognitive load for messaging interaction

## Implementation Notes

**Phase 1: Core Functionality**
1. Create DynamicTextInput component with UITextView
2. Implement sizeThatFits for dynamic height
3. Add keyboard observers to ChatView
4. Implement tap-to-dismiss gesture

**Phase 2: Polish**
5. Add message bubble animations
6. Enhance send button animations
7. Add focus state transitions
8. Add haptic feedback throughout

**Testing Checklist:**
- Input grows smoothly from 1-5 lines
- Keyboard appearance scrolls to bottom
- Tap blank area dismisses keyboard
- Send button disabled when no text/low energy
- Messages appear with smooth animations
- No layout jank during keyboard transitions
- Works on iPhone 13/14/15 simulator sizes

## Future Enhancements

(Out of scope for initial implementation)

- Typing indicators (show when other person is typing)
- Long-press message actions (copy, delete, react)
- Swipe-down to dismiss keyboard gesture
- Character counter near max length
- Voice input button
- Image/photo attachment support
- Read receipts / message status indicators

## References

- iOS 16+ UIViewRepresentable sizeThatFits() documentation
- Apple Messages app UX patterns
- Existing cozy design system (AppColors, AppSpacing, typography)
