Commit Graph

9 Commits

Author SHA1 Message Date
agra
b4b5ee58a9 feat: UxUrl — native URL / phone / email detection + tap launcher
Sync FFI from Dart into platform detectors:
- iOS / macOS: NSDataDetector(.link | .phoneNumber) + a tight bare-domain
  pass that requires `/` or `?` (so `etc.` / `v1.2.3` don't false-positive
  while `example.com/path` does match). NFKD-fold the phone capture so
  full-width / Arabic-Indic digits collapse to ASCII; stop the digit run
  at the first letter so `+1 555 1234 ext.99` doesn't fuse the extension.
- Android: JNI into android.util.Patterns (WEB_URL / EMAIL_ADDRESS / PHONE)
  via a cached JavaVM, std::call_once for init, full per-call
  ExceptionCheck coverage. UTF-16→UTF-8 conversion is hand-rolled to dodge
  the Modified-UTF-8 / CESU-8 incompatibility with Dart's utf8.decode.

`UxUrl.launch(url)` is the matching tap action. Channel side dispatches via
UIApplication / NSWorkspace / Intent.ACTION_VIEW. Dart-side gates the URL
against a scheme allowlist (http, https, mailto, tel, sms, banlu, tg),
rejects bidi-override controls (U+202A..E / U+2066..9) to prevent visual
spoofs, and blocks USSD / MMI tel: codes containing `*` or `#`.

Library/native cleanup along the way:
- Renamed libux_keyboard.so to libux.so (also covers sensor + url).
- Collapsed three near-identical FFI loader stanzas across keyboard / sensor
  / url into a shared lib/src/_ffi.dart with `uxLib` + typed `uxLookupX`
  helpers.
2026-05-14 22:59:25 +03:00
agra
0b5618948a camera podspec: mirror darwin/Camera on every build, not just pod install
`prepare_command` runs only on `pod install`. Mid-iteration Swift
edits to `darwin/Camera/*.swift` would never reach the built binary
until the user ran pod install or cleaned the Pods dir — confusing
during debugging (NSLog/diag additions silently absent from the
running app).

Add a `script_phases` build phase to both podspecs that rsyncs
darwin/Camera into Classes/Camera-shared before each compile. The
existing `prepare_command` stays as the install-time primer that
gives CocoaPods the initial file set to glob; the build phase keeps
contents fresh on every Swift edit thereafter. Verified: the resulting
binary now contains the NSLog strings that the prior build was
missing.

(Adding new files to darwin/Camera/ still requires pod install so
CocoaPods' source_files glob picks them up — script_phases only
refreshes content of files CocoaPods already knows about.)
2026-05-13 21:20:39 +03:00
agra
14565ebd7a camera: macOS port via darwin/ split (no shared-file pragmas)
Reuse the AVFoundation Swift files between iOS and macOS without
sprinkling `#if canImport(UIKit)` through them. The split is:

  darwin/Camera/                 platform-shared (AVFoundation only)
    CameraPlugin                 channel + instance map
    CameraInstance               session + outputs + texture
    CameraSession                AVCaptureSession + runtime-error obs
    CaptureDevice                front/back discovery
    PhotoOutput                  AVCapturePhotoOutput
    PreviewSink                  CVPixelBuffer → FlutterTexture
    VideoRecorder                AVAssetWriter
    DeviceOrientation            wire-string enum

  ios/Classes/Camera/            iOS-only impls + extensions
    AudioSession                 AVAudioSession.upgradeForRecording
    DeviceOrientationBridge      UIDevice.orientation listener
    CameraSession+iOS            AVCaptureSessionWasInterrupted obs
                                 + InterruptionReason decode + the
                                 application-audio-session flags
                                 (all iOS-only on AVCaptureSession)
    CameraSettings               UIApplication.openSettingsURLString
    FlutterRegistrar+iOS         method-form of textures/messenger

  macos/Classes/Camera/          macOS no-op stubs (same surface)
    AudioSession                 no-op (no AVAudioSession on macOS)
    DeviceOrientationBridge      no-op (desktops don't rotate)
    CameraSession+macOS          no-op setupPlatform()
    CameraSettings               NSWorkspace → System Settings'
                                 Privacy_Camera pane
    FlutterRegistrar+macOS       property-form of textures/messenger

`CameraSession.init` now calls `setupPlatform()` which each platform
provides via an extension — keeps the iOS-only interruption observer
and the `automaticallyConfiguresApplicationAudioSession` /
`usesApplicationAudioSession` flags (both iOS-only on AVCaptureSession)
out of the shared file. Flash-mode in PhotoOutput uses
`if #available(macOS 11/13, *)` rather than `#if`, since those are
plain version gates not platform splits.

The shared files compile into the iOS pod from `ios/Classes/Camera-shared/`
and into the macOS pod from `macos/Classes/Camera-shared/`, each a
mirror populated by a `prepare_command` in the podspec:

    rm -rf Classes/Camera-shared && cp -R ../darwin/Camera Classes/Camera-shared

Symlinks and `../` source globs both fail — Pathname.glob bails on
symlinks, and CocoaPods silently drops paths that escape the pod
directory. The mirror destinations are .gitignore'd.

macOS UxPlugin now registers CameraPlugin alongside the others.
2026-05-13 18:53:46 +03:00
agra
6d6a871c53 camera: iOS implementation (Phase 2+3)
Native plugin owning AVCaptureSession + AVAssetWriter, mirroring
telegram-iOS's Camera module decomposition. Photo + video capture with
the writer-track transform set from a per-call orientation snapshot
(the three-way preview/capture/device split that camera_avfoundation
can't give us).

Modules:
  CameraPlugin           channels + per-handle instance map
  CameraInstance         session + texture + outputs + recorder
  CameraSession          AVCaptureSession + runtime-error/interrupt obs
  CaptureDevice          front/back discovery, per-device config
  PhotoOutput            AVCapturePhotoOutput, per-shot orientation
  VideoRecorder          AVAssetWriter, lazy inputs, pending-audio queue,
                         stop()/cancel() pair (matches telegram)
  PreviewSink            CVPixelBuffer → FlutterTexture
  AudioSession           setCategory + setActive(true) (only-widen)
  DeviceOrientationBridge

Recorder details:
  - Lazy videoInput/audioInput on first sample, sourceFormatHint:.
  - Audio settings derived from CMAudioFormatDescriptionGet*
    + recommendedAudioSettingsForAssetWriter, gated startWriting.
  - Stop sets stopSampleTime; next sample crossing it triggers
    maybeFinish → finishWriting. No watchdog — telegram pattern.
  - cancel() drops pending audio + cancelWriting + deletes file,
    used by CameraInstance.dispose when teardown finds in-flight
    recording.
  - Diagnostic stream → ux/camera/events {event: "diagnostic"}.

Dart surface extensions over Phase 1:
  - UxCameraValue.audioPermissionGranted
  - UxCameraController.refreshAudioPermission()
  - Static UxCameraController.audioPermissionGranted() /
    openSystemSettings()
  - UxCameraDiagnostic event variant
  - FakeUxCameraBackend.{emitDiagnostic, audioPermission,
    openSettingsCalls}

Tests: 32/32 in test/camera (controller + channel) green.
2026-05-13 16:56:49 +03:00
agra
a587a7a967 gallery: link PhotosUI in podspec so the limited-picker category loads
Swift `import PhotosUI` made the compiler happy but the binary never
referenced any PhotosUI symbol directly — `presentLimitedLibraryPicker`
is dispatched via `objc_msgSend` against an Obj-C category on
`PHPhotoLibrary`. Without an explicit framework link the linker
dropped PhotosUI, the category never registered, and iOS 26 raised
NSInvalidArgumentException for an "unrecognized selector".

Declare Photos + PhotosUI as podspec frameworks so the linker force-
loads them.
2026-05-11 12:07:04 +03:00
agra
26cdf63afc scanner 2026-05-07 09:22:01 +03:00
agra
7e0b9a6330 files 2026-04-22 22:42:53 +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