Commit Graph

12 Commits

Author SHA1 Message Date
agra
77cda5a17e gallery: library-change Stream + native observer parity
Add UxGallery.libraryChanges — a Stream<void> that emits whenever the
underlying photo library reports a change, so picker UIs can drop
their cached asset lists and reload reactively.

- iOS: GalleryPlugin conforms to PHPhotoLibraryChangeObserver +
  FlutterStreamHandler; on photoLibraryDidChange the fetchCache is
  cleared and a void event is pushed over ux/gallery/changes. The
  observer is registered lazily on the first granted/limited
  authorization so plugin init doesn't trigger iOS's permission
  evaluation at app launch.
- macOS: near-verbatim port of the iOS shape (same Photos.framework,
  same fetchCache staleness, same fix).
- Android: registers a MediaStore ContentObserver on
  Files.getContentUri(VOLUME_EXTERNAL) with notifyForDescendants =
  true; observer lifecycle tracks the Dart subscription (registered
  on onListen, unregistered on onCancel / plugin detach). No native
  cache to invalidate today, but the pipeline is wired for the
  upcoming READ_MEDIA_VISUAL_USER_SELECTED limited-access work.
- iOS presentLimitedLibraryPicker switched to the iOS 15+ completion-
  handler variant so the Dart await resolves on dismissal, not on
  presentation. The actual reload is now driven by the change
  observer (which fires after iOS commits the new subset),
  side-stepping the completion-vs-commit race that produced an
  off-by-one in the picker on consecutive MANAGE taps.
- FakeUxGalleryBackend exposes emitLibraryChange() so tests can
  drive the reactive-reload wiring without going through the real
  method channel.
2026-05-11 09:52:17 +03:00
agra
3eba30358c ... 2026-05-10 16:37:23 +03:00
agra
fb00e98681 clipboard: add UxClipboard.readImage native bridge
Flutter's Clipboard API only exposes text shapes. Banlu's chat composer
needs image bytes from the system clipboard for desktop paste, so add
a UxClipboard facade backed by per-platform native plugins:

* iOS: prefer raw PNG/JPEG bytes off the pasteboard, fall back to
  re-encoding `UIPasteboard.image` as PNG.
* macOS: prefer NSPasteboard `.png`, fall back to TIFF transcoded
  through NSBitmapImageRep so screenshots / Preview hand-offs still
  work.
* Android: read primary ClipData's first item URI and stream the bytes
  through ContentResolver — don't trust the clip description's MIME,
  copy whatever the resolver returns.

Returns null (never throws) when the clipboard has no image — callers
treat null as "fall through to text paste".
2026-05-09 07:29:14 +03:00
agra
cc28782119 files 2026-05-07 12:56:00 +03:00
agra
26cdf63afc scanner 2026-05-07 09:22:01 +03:00
agra
6d8efafaa0 ... 2026-05-05 23:37:34 +03:00
agra
afc7e9c872 file: add path-only pick + native video thumbnail
Two new methods on `UxFile`, both designed to keep large file content
out of the platform-channel buffer (the failure mode of file_selector
on Android: a ~200 MB video PUT through the Pigeon codec OOM'd the
JVM via `byte[size]` allocation in `FileSelectorApiImpl`).

`UxFile.pick({mimeTypes})` returns `UxPickedFile?` with `path`, `name`,
`mimeType`, `size`. The platform channel reply carries only the
metadata; bytes never cross.
  - Android: `ACTION_OPEN_DOCUMENT` + `EXTRA_MIME_TYPES`, registered
    as `ActivityResultListener`. On result, stream-copies the SAF
    content URI to `cacheDir/ux_pick/<ts>_<safeName>` via an 8 KB
    buffer (no full-file allocation in JVM heap), returns the cache
    path.
  - iOS: `UIDocumentPickerViewController(documentTypes:in: .import)`
    — `.import` mode copies the picked file into the app's
    Documents/Inbox so the URL is stable. Strong-retained delegate
    (the picker's delegate ref is weak).
  - macOS: `NSOpenPanel` with `allowedFileTypes`. Sheet-modal when a
    Flutter window exists; free-modal otherwise.

`UxFile.videoThumbnail({path, atMs, maxWidth})` returns
`UxVideoThumbnail?` (PNG bytes + dims).
  - Android: `MediaMetadataRetriever.getFrameAtTime(..., OPTION_CLOSEST_SYNC)`,
    `Bitmap.createScaledBitmap` to maxWidth, PNG-encode via
    `ByteArrayOutputStream`, recycle bitmaps in `finally`, release
    retriever in `finally`.
  - iOS: `AVAssetImageGenerator` with `appliesPreferredTrackTransform = true`,
    `maximumSize = (maxWidth, 0)` (preserve aspect), ±500 ms tolerance
    for keyframe alignment, decode on `userInitiated` queue.
  - macOS: same generator, encoded via `NSBitmapImageRep`.

Compatible with the package's existing iOS 13 / macOS 10.15 deployment
targets — uses legacy `kUTType*` + `UTTypeCreatePreferredIdentifierForTag`
instead of `UTType` (iOS 14 / macOS 11).
2026-05-02 13:14:21 +03:00
agra
7e0b9a6330 files 2026-04-22 22:42:53 +03:00
agra
2113537078 orientation 2026-04-22 16:22:45 +03:00
agra
b8d77e0a3a keyboard focus + app_info 2026-04-21 16:54:56 +03:00
agra
0be198e388 android: keyboard height tracking via JNI/FFI bridge
- C bridge (keyboard_bridge.c) stores keyboard state in globals.
  Kotlin writes via JNI, Dart reads via FFI — zero async delay,
  same architecture as iOS.
- WindowInsetsAnimation.Callback tracks open/close per-frame.
- OnGlobalLayoutListener catches silent height changes (emoji
  keyboard resize, floating keyboard toggle).
- Dart animation replay stays iOS-only; Android reads native
  per-frame values directly.
- Cleaned up old Java stub, updated build.gradle for Kotlin + CMake
  with 16KB page alignment (Android 15+).
- Example app rewritten to demonstrate UxKeyboard usage.
2026-04-15 23:49:16 +03:00
agrapine
810d060d44 red pill 2019-08-07 15:37:44 +01:00