feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
part of '../compose_bar.dart';
|
||||
|
||||
const _inlinePhotoPickerViewType = 'buzz/inline_photo_picker';
|
||||
const _inlinePhotoPickerSupportChannel = MethodChannel(
|
||||
'buzz/inline_photo_picker',
|
||||
);
|
||||
|
||||
class _IOSInlinePhotoPicker extends HookWidget {
|
||||
final VoidCallback onBack;
|
||||
final Future<List<XFile>> Function() onPickAllPhotos;
|
||||
final Future<void> Function(List<XFile> photos) onChoosePhotos;
|
||||
final Future<void> Function(List<XFile> photos) onChooseAllPhotos;
|
||||
final Widget fallback;
|
||||
|
||||
const _IOSInlinePhotoPicker({
|
||||
required this.onBack,
|
||||
required this.onPickAllPhotos,
|
||||
required this.onChoosePhotos,
|
||||
required this.onChooseAllPhotos,
|
||||
required this.fallback,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final supportFuture = useMemoized(
|
||||
() async =>
|
||||
await _inlinePhotoPickerSupportChannel.invokeMethod<bool>(
|
||||
'isSupported',
|
||||
) ??
|
||||
false,
|
||||
);
|
||||
final support = useFuture(supportFuture);
|
||||
final pickerChannel = useState<MethodChannel?>(null);
|
||||
final selectedCount = useState(0);
|
||||
final selectedPaths = useState<List<String>>(const []);
|
||||
final isPreparingSelection = useState(false);
|
||||
final isProcessing = useState(false);
|
||||
|
||||
useEffect(() {
|
||||
final channel = pickerChannel.value;
|
||||
if (channel == null) return null;
|
||||
|
||||
channel.setMethodCallHandler((call) async {
|
||||
switch (call.method) {
|
||||
case 'selectionCountChanged':
|
||||
selectedCount.value = call.arguments as int? ?? 0;
|
||||
selectedPaths.value = const [];
|
||||
isPreparingSelection.value = selectedCount.value > 0;
|
||||
case 'selectionDidChange':
|
||||
final paths = (call.arguments as List<Object?>? ?? const [])
|
||||
.whereType<String>()
|
||||
.toList();
|
||||
selectedPaths.value = paths;
|
||||
isPreparingSelection.value = false;
|
||||
case 'didFail':
|
||||
isPreparingSelection.value = false;
|
||||
if (!context.mounted) return;
|
||||
ScaffoldMessenger.maybeOf(context)?.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
call.arguments as String? ??
|
||||
context.l10n.preparingPhotos,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
return () => channel.setMethodCallHandler(null);
|
||||
}, [pickerChannel.value]);
|
||||
|
||||
final canSelect =
|
||||
selectedCount.value > 0 &&
|
||||
selectedPaths.value.length == selectedCount.value &&
|
||||
!isPreparingSelection.value &&
|
||||
!isProcessing.value;
|
||||
|
||||
Future<void> submitSelection() async {
|
||||
if (!canSelect) return;
|
||||
isProcessing.value = true;
|
||||
try {
|
||||
final paths = List<String>.from(selectedPaths.value);
|
||||
final claimed =
|
||||
await pickerChannel.value?.invokeMethod<bool>(
|
||||
'claimSelection',
|
||||
paths,
|
||||
) ??
|
||||
false;
|
||||
if (!claimed) return;
|
||||
final photos = [for (final path in paths) XFile(path)];
|
||||
await processTemporaryImages(photos, onChoosePhotos);
|
||||
} finally {
|
||||
if (context.mounted) isProcessing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> openAllPhotos() async {
|
||||
if (isPreparingSelection.value || isProcessing.value) return;
|
||||
isProcessing.value = true;
|
||||
try {
|
||||
final photos = await onPickAllPhotos();
|
||||
if (photos.isNotEmpty) {
|
||||
await onChooseAllPhotos(photos);
|
||||
}
|
||||
} catch (_) {
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.maybeOf(context)?.showSnackBar(
|
||||
SnackBar(content: Text(context.l10n.unablePhotoLibrary)),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (context.mounted) isProcessing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (support.connectionState != ConnectionState.done) {
|
||||
return const _NativePhotoPickerLoading();
|
||||
}
|
||||
if (support.hasError || support.data != true) return fallback;
|
||||
|
||||
return SizedBox(
|
||||
key: const ValueKey('ios-inline-photo-picker'),
|
||||
height: _attachmentExpandedHeight,
|
||||
width: double.infinity,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
UiKitView(
|
||||
viewType: _inlinePhotoPickerViewType,
|
||||
creationParamsCodec: const StandardMessageCodec(),
|
||||
onPlatformViewCreated: (viewId) {
|
||||
pickerChannel.value = MethodChannel(
|
||||
'buzz/inline_photo_picker/$viewId',
|
||||
);
|
||||
},
|
||||
),
|
||||
PositionedDirectional(
|
||||
start: Grid.twelve,
|
||||
bottom: Grid.twelve,
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.62),
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: Colors.white.withValues(alpha: 0.28),
|
||||
),
|
||||
),
|
||||
child: IconButton(
|
||||
key: const ValueKey('ios-inline-photo-picker-back'),
|
||||
onPressed: isProcessing.value
|
||||
? null
|
||||
: () => _runComposerAction(onBack),
|
||||
tooltip: context.l10n.backAttachmentOptions,
|
||||
icon: const Icon(
|
||||
LucideIcons.chevronLeft,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
PositionedDirectional(
|
||||
end: Grid.twelve,
|
||||
bottom: Grid.twelve,
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: FilledButton(
|
||||
key: const ValueKey('ios-inline-photo-picker-select'),
|
||||
onPressed: canSelect
|
||||
? () =>
|
||||
_runComposerAction(() => unawaited(submitSelection()))
|
||||
: selectedCount.value == 0 &&
|
||||
!isPreparingSelection.value &&
|
||||
!isProcessing.value
|
||||
? () => _runComposerAction(() => unawaited(openAllPhotos()))
|
||||
: null,
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: Colors.black.withValues(alpha: 0.76),
|
||||
disabledBackgroundColor: Colors.black.withValues(alpha: 0.32),
|
||||
foregroundColor: Colors.white,
|
||||
disabledForegroundColor: Colors.white70,
|
||||
minimumSize: const Size(0, 48),
|
||||
padding: const EdgeInsets.symmetric(horizontal: Grid.twelve),
|
||||
shape: const StadiumBorder(),
|
||||
side: BorderSide(color: Colors.white.withValues(alpha: 0.28)),
|
||||
),
|
||||
child: isPreparingSelection.value
|
||||
? SizedBox.square(
|
||||
dimension: 20,
|
||||
child: BuzzLoadingIndicator(
|
||||
size: 20,
|
||||
color: Colors.white,
|
||||
semanticLabel: context.l10n.preparingPhotos,
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
selectedCount.value == 0
|
||||
? context.l10n.allPhotos
|
||||
: context.l10n.addPhoto(selectedCount.value),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isProcessing.value)
|
||||
ColoredBox(
|
||||
color: Color.fromRGBO(0, 0, 0, 0.28),
|
||||
child: Center(
|
||||
child: BuzzLoadingIndicator(
|
||||
size: 44,
|
||||
color: Colors.white,
|
||||
semanticLabel: context.l10n.preparingPhotos,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NativePhotoPickerLoading extends StatelessWidget {
|
||||
const _NativePhotoPickerLoading();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
key: const ValueKey('ios-inline-photo-picker-loading'),
|
||||
height: _attachmentExpandedHeight,
|
||||
width: double.infinity,
|
||||
child: Center(
|
||||
child: BuzzLoadingIndicator(
|
||||
size: 44,
|
||||
semanticLabel: context.l10n.openingPhotos,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user