agra a6d2539722 camera: macOS device discovery now includes external + Continuity
Discovery was hard-coded to `.builtInWideAngleCamera` only — that
catches the iOS front/back cameras and the macOS FaceTime HD on
macOS 14+, but missed USB webcams (`.external` on 14+,
`.externalUnknown` before) and iPhone-as-webcam Continuity Camera
(`.continuityCamera` on 14+). On Macs whose built-in camera doesn't
expose itself as `.builtInWideAngleCamera`, the result was "no
camera detected".

Device types are now platform-conditional: iOS keeps the wide-angle
filter as-is; macOS adds the externals + Continuity (gated via
`if #available(macOS 14.0, *)` for the post-14 forms vs the
deprecated `.externalUnknown` for older macOS). The `#if os(macOS)`
guard is unavoidable — `.external` and friends literally aren't
declared as enum cases on iOS.
2026-05-13 18:58:37 +03:00
...
2026-05-10 16:37:23 +03:00
2019-08-07 15:37:44 +01:00
2026-04-21 16:54:56 +03:00
2026-05-07 09:22:01 +03:00
2019-10-17 14:34:21 +01:00
2026-05-07 09:22:01 +03:00
2026-04-16 18:42:55 +03:00
zzz
2020-05-04 10:58:19 +01:00

ux

A Flutter toolkit for building fluid, native-feeling UIs.

UxKeyboard

Frame-accurate keyboard height tracking for iOS and Android, with interactive dismiss.

Flutter's built-in MediaQuery.viewInsets.bottom lags behind the actual keyboard position and doesn't support interactive dismiss. UxKeyboard reads the keyboard height directly from the native layer via FFI — zero channel latency, every frame.

Features

  • Real-time height — reads the keyboard's actual position each frame via FFI (iOS) / JNI (Android)
  • Native animation curves — sampled from CADisplayLink (iOS) and WindowInsetsAnimation (Android), with adaptive learning that refines the curve from observations
  • Interactive dismiss — swipe the keyboard down like iMessage/Telegram, with snap-back or dismiss
  • Scroll freezeisTracking flag lets you freeze scrolling during interactive dismiss

Quick start

final keyboard = UxKeyboard.instance;

// Enable swipe-to-dismiss. trackingInset is the height of your input bar.
keyboard.enableInteractiveDismiss(trackingInset: 56);

Use ListenableBuilder to rebuild when the keyboard height changes:

Scaffold(
  resizeToAvoidBottomInset: false, // we handle it ourselves
  body: ListenableBuilder(
    listenable: keyboard,
    builder: (context, _) {
      final keyboardHeight = keyboard.height;
      final safeBottom = MediaQuery.viewPaddingOf(context).bottom;
      final bottom = max(keyboardHeight, safeBottom);

      return Column(
        children: [
          Expanded(
            child: ListView.builder(
              reverse: true,
              // Freeze scrolling during interactive dismiss
              physics: keyboard.isTracking
                  ? NeverScrollableScrollPhysics()
                  : null,
              // ...
            ),
          ),
          Container(
            padding: EdgeInsets.only(bottom: 8 + bottom),
            // your input bar
          ),
        ],
      );
    },
  ),
);

API

Member Description
UxKeyboard.instance Singleton instance
.height Current keyboard height in logical pixels
.systemHeight Last system-reported keyboard height
.isOpen Whether the keyboard is visible
.isTracking Whether a dismiss pan gesture is active
.enableInteractiveDismiss({trackingInset}) Enable swipe-to-dismiss
.disableInteractiveDismiss() Disable swipe-to-dismiss
addListener / removeListener Standard ChangeNotifier API

Key points

  • Set resizeToAvoidBottomInset: false on your Scaffold — otherwise Flutter's built-in resize fights with UxKeyboard
  • Use MediaQuery.viewPaddingOf(context).bottom for the safe area (not paddingOf, which is consumed by Scaffold)
  • Use max(keyboardHeight, safeBottom) for bottom padding — the keyboard height includes the safe area when open, and safeBottom covers the home indicator when closed

Other utilities

  • BendBox — a flexible layout widget
  • Bezier — bezier curve utilities
Description
No description provided
Readme MIT 1.5 MiB
Languages
Dart 40.2%
Swift 29.1%
Kotlin 18.4%
Java 5.2%
C++ 3.1%
Other 4%