Skip to content

Footer

Metadata

  • System type: library

System Intent

  • What this is: A React Native component that renders the bottom action bar of the main screen. It composes three interactive elements: a device-picker button (left), the CaptureButton (center), and a chat-navigation button (right). It owns the DevicePickerSheet and exposes openDeviceSheet to both the device-picker button and the CaptureButton via the onGlassesUnavailable prop — so that pressing record while glasses are unavailable automatically opens the device picker rather than failing silently. When hideRecordButtons is true the component returns null immediately, hiding all record controls; this is used by memory-viewer-modal so that the record buttons do not appear while the user is viewing a memory.

Mermaid Diagram

flowchart TD
  HideCheck{hideRecordButtons?}
  HideCheck -->|true| ReturnNull["return null<br/>no rendering"]
  HideCheck -->|false| FooterMount([Footer renders])

  FooterMount --> CB[CaptureButton\nonGlassesUnavailable=openDeviceSheet]
  FooterMount --> DevBtn[Device picker button\nonPress=openDeviceSheet]
  FooterMount --> ChatBtn[Chat button\nonPress=router.push /chat]

  DevBtn -->|idle only| OpenSheet[openDeviceSheet]
  CB -->|glasses mode + not connected| OpenSheet

  OpenSheet --> Log[log device_picker_open]
  Log --> RefreshAvail[isGlassesDeviceAvailable — refresh]
  RefreshAvail --> ShowSheet[setSheetVisible true]

  ShowSheet --> Sheet[DevicePickerSheet]
  Sheet -->|select device| SelectDevice[setSelectedRecordingDevice\nsetSheetVisible false\nlog device_select]
  Sheet -->|close| CloseSheet[setSheetVisible false\nlog device_picker_close]

Flows

Flow: hideRecordButtons.earlyReturn

  • Test files: main/app/__tests__/memory-viewer-modal.test.tsx
  • Core files: main/app/components/footer.tsx

Paths

path input output path-type notes
hideRecordButtons.earlyReturn hideRecordButtons={true} is passed (e.g. by memory-viewer-modal) component returns null; no record controls rendered happy path used wherever record buttons must not appear, such as when a memory detail is open

Flow: openDeviceSheet

  • Test files: main/app/__tests__/footer.test.tsx
  • Core files: main/app/components/footer.tsx

Types

FooterProps {
  bottomInset?: number        (default 0; added to the 24 px bottom offset)
  onLayout?: (event: LayoutChangeEvent) => void
  hideRecordButtons?: boolean (default false; when true the component renders null — no record controls are shown)
}

RecordingDevice = "glasses" | "glasses-audio" | "phone" | ...

Paths

path input output path-type notes
openDeviceSheet.fromDeviceButton user presses device-picker button while idle sheet opens; glassesAvailable refreshed; device_picker_open logged happy path device-picker button is disabled when not idle
openDeviceSheet.fromCaptureButton CaptureButton fires onGlassesUnavailable (glasses mode + not connected) same as above — sheet opens; glassesAvailable refreshed; device_picker_open logged happy path fail-fast path from CaptureButton; no recording was attempted
hideRecordButtons.earlyReturn hideRecordButtons={true} is passed (e.g. by memory-viewer-modal) component returns null; no record controls rendered happy path used wherever record buttons must not appear, such as when a memory is open

Flow: handleSelectDevice

  • Core files: main/app/components/footer.tsx

Paths

path input output path-type notes
handleSelectDevice.success user selects a device in the sheet setSelectedRecordingDevice(device) persisted; sheet closed; device_select logged happy path

Flow: handleSheetClose

  • Core files: main/app/components/footer.tsx

Paths

path input output path-type notes
handleSheetClose.success user dismisses sheet without selecting sheet closed; device_picker_close logged happy path

Logs

Source Location
device_picker_open useLogging() frontend logger — includes { selectedDevice, glassesAvailable }
device_picker_close useLogging() frontend logger — includes { selectedDevice }
device_select useLogging() frontend logger — includes { device, previousDevice }

Deployment

  • Mechanism: local only (shipped as part of the React Native app bundle)
  • Deploy command:
    cd main && npx expo start
    
  • Notes: The device-picker button is disabled (disabled={!idle}) while a recording is in progress or transitioning, preventing device changes mid-session. glassesAvailable state is refreshed synchronously on every openDeviceSheet call so the sheet always reflects the current Bluetooth connection state at the moment it opens. When hideRecordButtons={true} is passed, the component returns null without rendering anything, used to hide footer buttons in contexts like the memory detail viewer modal.