ux: bulk WIP — UxPlugin→XPlugin rename + new anim/core/navi/reactive packages
Catch-all commit for outstanding pre-existing local changes. Mixes several themes that would normally be split: - Rename: UxPlugin → XPlugin across iOS, macOS, Android registrants. - New top-level packages under lib/src/: anim/ (animated values, panes, sheets, dock, measured), core/ (Emitter, ReactiveBuilder scaffolding, presenter/widget/value/dispose primitives), navi/ (Screen/ScreenStack/Router/hero/transitions), reactive/. - Edits across existing plugins (clipboard, crash, file, gallery, keyboard, scanner, sensor, url) to align with the new core. - Test updates and CHANGELOG/README touches accompanying the above.
This commit is contained in:
@@ -8,7 +8,7 @@ import AVFoundation
|
||||
/// the result. The macOS counterpart in
|
||||
/// `macos/Classes/Camera/AVCaptureConnection+macOS.swift` is a no-op.
|
||||
extension AVCaptureConnection {
|
||||
func applyUxCaptureOrientation(_ orientation: DeviceOrientationFlutter) {
|
||||
func applyXCaptureOrientation(_ orientation: DeviceOrientationFlutter) {
|
||||
if isVideoOrientationSupported {
|
||||
videoOrientation = orientation.avVideoOrientation
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import UIKit
|
||||
public class FilePlugin: NSObject, NativePlugin {
|
||||
private var channel: FlutterMethodChannel?
|
||||
private var previewDataSource: FilePreviewDataSource?
|
||||
private var pickerDelegate: UxDocumentPickerDelegate?
|
||||
private var pickerDelegate: XDocumentPickerDelegate?
|
||||
|
||||
private struct ScopedEntry {
|
||||
let url: URL
|
||||
@@ -91,7 +91,7 @@ public class FilePlugin: NSObject, NativePlugin {
|
||||
let path = args["path"] as? String else {
|
||||
return result(FlutterError(code: "bad_args", message: "path is required", details: nil))
|
||||
}
|
||||
guard let topVC = UxWindow.topViewController else {
|
||||
guard let topVC = XWindow.topViewController else {
|
||||
return result(FlutterError(code: "no_view", message: "no top view controller", details: nil))
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public class FilePlugin: NSObject, NativePlugin {
|
||||
}
|
||||
|
||||
private func handlePick(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
guard let topVC = UxWindow.topViewController else {
|
||||
guard let topVC = XWindow.topViewController else {
|
||||
return result(FlutterError(code: "no_view", message: "no top view controller", details: nil))
|
||||
}
|
||||
let args = call.arguments as? [String: Any]
|
||||
@@ -136,7 +136,7 @@ public class FilePlugin: NSObject, NativePlugin {
|
||||
// cold starts.
|
||||
let picker = UIDocumentPickerViewController(documentTypes: utis, in: .open)
|
||||
picker.allowsMultipleSelection = false
|
||||
let delegate = UxDocumentPickerDelegate(result: result) { [weak self] in
|
||||
let delegate = XDocumentPickerDelegate(result: result) { [weak self] in
|
||||
self?.pickerDelegate = nil
|
||||
}
|
||||
// The delegate is weak on UIDocumentPickerViewController; keep a strong ref.
|
||||
@@ -180,7 +180,7 @@ public class FilePlugin: NSObject, NativePlugin {
|
||||
let path = args["path"] as? String else {
|
||||
return result(FlutterError(code: "bad_args", message: "path is required", details: nil))
|
||||
}
|
||||
guard let topVC = UxWindow.topViewController else {
|
||||
guard let topVC = XWindow.topViewController else {
|
||||
return result(FlutterError(code: "no_view", message: "no top view controller", details: nil))
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ fileprivate func mimeFromExtension(_ ext: String) -> String? {
|
||||
/// we briefly start access to read attributes + create a bookmark, then
|
||||
/// stop access. Persisted bookmark lets Dart re-acquire scope later via
|
||||
/// `beginScopedAccess`.
|
||||
private final class UxDocumentPickerDelegate: NSObject, UIDocumentPickerDelegate {
|
||||
private final class XDocumentPickerDelegate: NSObject, UIDocumentPickerDelegate {
|
||||
let result: FlutterResult
|
||||
let onDone: () -> Void
|
||||
private var settled = false
|
||||
|
||||
@@ -3,7 +3,7 @@ import Photos
|
||||
import PhotosUI
|
||||
import UIKit
|
||||
|
||||
/// `Photos.framework` bridge for `UxGallery` — paginated asset queries,
|
||||
/// `Photos.framework` bridge for `XGallery` — paginated asset queries,
|
||||
/// cell-sized thumbnails via `PHCachingImageManager`, and on-demand
|
||||
/// file resolution into the app cache.
|
||||
public class GalleryPlugin: NSObject, NativePlugin, PHPhotoLibraryChangeObserver, FlutterStreamHandler {
|
||||
@@ -101,7 +101,7 @@ public class GalleryPlugin: NSObject, NativePlugin, PHPhotoLibraryChangeObserver
|
||||
// Completion handler signals dismissal; reload is driven by
|
||||
// `ux/gallery/changes` via the library observer (fires after
|
||||
// iOS commits the new subset).
|
||||
if #available(iOS 15, *), let vc = UxWindow.topViewController {
|
||||
if #available(iOS 15, *), let vc = XWindow.topViewController {
|
||||
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: vc) { _ in
|
||||
// Apple's docs: the completion handler runs on "an
|
||||
// arbitrary serial dispatch queue". Flutter method-
|
||||
@@ -110,7 +110,7 @@ public class GalleryPlugin: NSObject, NativePlugin, PHPhotoLibraryChangeObserver
|
||||
result(nil)
|
||||
}
|
||||
}
|
||||
} else if #available(iOS 14, *), let vc = UxWindow.topViewController {
|
||||
} else if #available(iOS 14, *), let vc = XWindow.topViewController {
|
||||
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: vc)
|
||||
result(nil)
|
||||
} else {
|
||||
|
||||
@@ -268,7 +268,7 @@ public class KeyboardPlugin: NSObject, NativePlugin {
|
||||
}
|
||||
|
||||
private func setupPanGesture() {
|
||||
guard let window = UxWindow.keyWindow else { return }
|
||||
guard let window = XWindow.keyWindow else { return }
|
||||
let view: UIView = window.rootViewController?.view ?? window
|
||||
|
||||
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
|
||||
|
||||
@@ -5,7 +5,7 @@ public protocol NativePlugin {
|
||||
func register(with registrar: FlutterPluginRegistrar)
|
||||
}
|
||||
|
||||
public enum UxWindow {
|
||||
public enum XWindow {
|
||||
public static var keyWindow: UIWindow? {
|
||||
if let w = UIApplication.shared.delegate?.window ?? nil { return w }
|
||||
for scene in UIApplication.shared.connectedScenes {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
public class UxPlugin: NSObject, FlutterPlugin {
|
||||
public class XPlugin: NSObject, FlutterPlugin {
|
||||
private static var plugins: [NativePlugin] = []
|
||||
|
||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||
@@ -1,4 +1,4 @@
|
||||
// Native data detection for UxUrl. Synchronous, callable via dart:ffi.
|
||||
// Native data detection for XUrl. Synchronous, callable via dart:ffi.
|
||||
//
|
||||
// Exports two symbols:
|
||||
// uint8_t* ux_match_url(const uint16_t* utf16, int32_t len, int32_t* out_size);
|
||||
@@ -24,13 +24,13 @@ static const uint32_t kKindWeb = 0;
|
||||
static const uint32_t kKindEmail = 1;
|
||||
static const uint32_t kKindPhone = 2;
|
||||
|
||||
@interface UxUrlRawMatch : NSObject
|
||||
@interface XUrlRawMatch : NSObject
|
||||
@property (nonatomic) int32_t start;
|
||||
@property (nonatomic) int32_t end;
|
||||
@property (nonatomic) uint32_t kind;
|
||||
@property (nonatomic, copy) NSData *urlUtf8;
|
||||
@end
|
||||
@implementation UxUrlRawMatch
|
||||
@implementation XUrlRawMatch
|
||||
@end
|
||||
|
||||
static NSDataDetector *ux_url_data_detector(void) {
|
||||
@@ -76,7 +76,7 @@ uint8_t *ux_match_url(const uint16_t *utf16, int32_t len, int32_t *out_size) {
|
||||
if (text.length == 0) return NULL;
|
||||
|
||||
NSRange whole = NSMakeRange(0, text.length);
|
||||
NSMutableArray<UxUrlRawMatch *> *raws = [NSMutableArray array];
|
||||
NSMutableArray<XUrlRawMatch *> *raws = [NSMutableArray array];
|
||||
|
||||
NSDataDetector *detector = ux_url_data_detector();
|
||||
if (detector != nil) {
|
||||
@@ -130,7 +130,7 @@ uint8_t *ux_match_url(const uint16_t *utf16, int32_t len, int32_t *out_size) {
|
||||
}
|
||||
if (url.length == 0) return;
|
||||
|
||||
UxUrlRawMatch *m = [[UxUrlRawMatch alloc] init];
|
||||
XUrlRawMatch *m = [[XUrlRawMatch alloc] init];
|
||||
m.start = (int32_t)r.location;
|
||||
m.end = (int32_t)(r.location + r.length);
|
||||
m.kind = kind;
|
||||
@@ -152,7 +152,7 @@ uint8_t *ux_match_url(const uint16_t *utf16, int32_t len, int32_t *out_size) {
|
||||
if (r.location == NSNotFound || r.length == 0) return;
|
||||
NSString *substr = [text substringWithRange:r];
|
||||
NSString *withScheme = [@"http://" stringByAppendingString:substr];
|
||||
UxUrlRawMatch *m = [[UxUrlRawMatch alloc] init];
|
||||
XUrlRawMatch *m = [[XUrlRawMatch alloc] init];
|
||||
m.start = (int32_t)r.location;
|
||||
m.end = (int32_t)(r.location + r.length);
|
||||
m.kind = kKindWeb;
|
||||
@@ -164,7 +164,7 @@ uint8_t *ux_match_url(const uint16_t *utf16, int32_t len, int32_t *out_size) {
|
||||
if (raws.count == 0) return NULL;
|
||||
|
||||
// Sort: start asc, then length desc, then kind desc (phone > email > web on tie).
|
||||
[raws sortUsingComparator:^NSComparisonResult(UxUrlRawMatch *a, UxUrlRawMatch *b) {
|
||||
[raws sortUsingComparator:^NSComparisonResult(XUrlRawMatch *a, XUrlRawMatch *b) {
|
||||
if (a.start != b.start) return a.start < b.start ? NSOrderedAscending : NSOrderedDescending;
|
||||
int32_t la = a.end - a.start;
|
||||
int32_t lb = b.end - b.start;
|
||||
@@ -174,10 +174,10 @@ uint8_t *ux_match_url(const uint16_t *utf16, int32_t len, int32_t *out_size) {
|
||||
}];
|
||||
|
||||
// Greedy de-overlap.
|
||||
NSMutableArray<UxUrlRawMatch *> *kept = [NSMutableArray arrayWithCapacity:raws.count];
|
||||
NSMutableArray<XUrlRawMatch *> *kept = [NSMutableArray arrayWithCapacity:raws.count];
|
||||
int32_t lastEnd = 0;
|
||||
BOOL haveAny = NO;
|
||||
for (UxUrlRawMatch *m in raws) {
|
||||
for (XUrlRawMatch *m in raws) {
|
||||
if (haveAny && m.start < lastEnd) continue;
|
||||
[kept addObject:m];
|
||||
lastEnd = m.end;
|
||||
@@ -185,7 +185,7 @@ uint8_t *ux_match_url(const uint16_t *utf16, int32_t len, int32_t *out_size) {
|
||||
}
|
||||
|
||||
NSUInteger total = 4;
|
||||
for (UxUrlRawMatch *m in kept) {
|
||||
for (XUrlRawMatch *m in kept) {
|
||||
total += 16 + (NSUInteger)m.urlUtf8.length;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ uint8_t *ux_match_url(const uint16_t *utf16, int32_t len, int32_t *out_size) {
|
||||
uint32_t cnt = (uint32_t)kept.count;
|
||||
memcpy(buf, &cnt, 4);
|
||||
NSUInteger off = 4;
|
||||
for (UxUrlRawMatch *m in kept) {
|
||||
for (XUrlRawMatch *m in kept) {
|
||||
int32_t start = m.start;
|
||||
int32_t end = m.end;
|
||||
uint32_t kind = m.kind;
|
||||
|
||||
Reference in New Issue
Block a user