Drag to upload

This commit is contained in:
LittleSheep 2024-06-29 20:25:29 +08:00
parent 85bba21285
commit e336d2372a
15 changed files with 304 additions and 160 deletions

View File

@ -30,6 +30,13 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<provider
android:name="com.superlist.super_native_extensions.DataProvider"
android:authorities="dev.solsynth.solian.SuperClipboardDataProvider"
android:exported="true"
android:grantUriPermissions="true" >
</provider>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

View File

@ -33,7 +33,9 @@ void main() async {
appRunner: () async { appRunner: () async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await protocolHandler.register('solink'); if (!PlatformInfo.isWeb) {
await protocolHandler.register('solink');
}
await Firebase.initializeApp( await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform, options: DefaultFirebaseOptions.currentPlatform,

View File

@ -179,7 +179,7 @@ class AccountProvider extends GetxController {
Future<void> registerPushNotifications() async { Future<void> registerPushNotifications() async {
final AuthProvider auth = Get.find(); final AuthProvider auth = Get.find();
if (!await auth.isAuthorized) throw Exception('unauthorized'); if (!await auth.isAuthorized) return;
late final String? token; late final String? token;
late final String provider; late final String provider;

View File

@ -1,21 +1,40 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'dart:typed_data';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:path/path.dart'; import 'package:path/path.dart';
import 'package:solian/platform.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/services.dart'; import 'package:solian/services.dart';
import 'package:image/image.dart' as img; import 'package:image/image.dart' as img;
Future<String> calculateFileSha256(File file) async { Future<String> calculateBytesSha256(Uint8List data) async {
final bytes = await Isolate.run(() => file.readAsBytesSync()); Digest digest;
final digest = await Isolate.run(() => sha256.convert(bytes)); if (PlatformInfo.isWeb) {
digest = sha256.convert(data);
} else {
digest = await Isolate.run(() => sha256.convert(data));
}
return digest.toString(); return digest.toString();
} }
Future<String> calculateFileSha256(File file) async {
Uint8List bytes;
if (PlatformInfo.isWeb) {
bytes = await file.readAsBytes();
} else {
bytes = await Isolate.run(() => file.readAsBytesSync());
}
return await calculateBytesSha256(bytes);
}
Future<double> calculateFileAspectRatio(File file) async { Future<double> calculateFileAspectRatio(File file) async {
if (PlatformInfo.isWeb) {
return 1;
}
final bytes = await Isolate.run(() => file.readAsBytesSync()); final bytes = await Isolate.run(() => file.readAsBytesSync());
final decoder = await Isolate.run(() => img.findDecoderForData(bytes)); final decoder = await Isolate.run(() => img.findDecoderForData(bytes));
if (decoder == null) return 1; if (decoder == null) return 1;
@ -25,7 +44,10 @@ Future<double> calculateFileAspectRatio(File file) async {
} }
class AttachmentProvider extends GetConnect { class AttachmentProvider extends GetConnect {
static Map<String, String> mimetypeOverrides = {'mov': 'video/quicktime'}; static Map<String, String> mimetypeOverrides = {
'mov': 'video/quicktime',
'mp4': 'video/mp4'
};
@override @override
void onInit() { void onInit() {
@ -45,7 +67,8 @@ class AttachmentProvider extends GetConnect {
return resp; return resp;
} }
Future<Response> createAttachment(File file, String hash, String usage, Future<Response> createAttachment(
Uint8List data, String path, String hash, String usage,
{double? ratio}) async { {double? ratio}) async {
final AuthProvider auth = Get.find(); final AuthProvider auth = Get.find();
if (!await auth.isAuthorized) throw Exception('unauthorized'); if (!await auth.isAuthorized) throw Exception('unauthorized');
@ -55,13 +78,12 @@ class AttachmentProvider extends GetConnect {
timeout: const Duration(minutes: 3), timeout: const Duration(minutes: 3),
); );
final filePayload = final filePayload = MultipartFile(data, filename: basename(path));
MultipartFile(await file.readAsBytes(), filename: basename(file.path)); final fileAlt = basename(path).contains('.')
final fileAlt = basename(file.path).contains('.') ? basename(path).substring(0, basename(path).lastIndexOf('.'))
? basename(file.path).substring(0, basename(file.path).lastIndexOf('.')) : basename(path);
: basename(file.path); final fileExt = basename(path)
final fileExt = basename(file.path) .substring(basename(path).lastIndexOf('.') + 1)
.substring(basename(file.path).lastIndexOf('.') + 1)
.toLowerCase(); .toLowerCase();
// Override for some files cannot be detected mimetype by server-side // Override for some files cannot be detected mimetype by server-side

View File

@ -88,7 +88,8 @@ class _PersonalizeScreenState extends State<PersonalizeScreen> {
final file = File(image.path); final file = File(image.path);
final hash = await calculateFileSha256(file); final hash = await calculateFileSha256(file);
attachResp = await provider.createAttachment( attachResp = await provider.createAttachment(
file, await file.readAsBytes(),
file.path,
hash, hash,
'p.$position', 'p.$position',
ratio: await calculateFileAspectRatio(file), ratio: await calculateFileAspectRatio(file),

View File

@ -178,12 +178,6 @@ class _AttachmentListState extends State<AttachmentList> {
); );
} }
@override
void initState() {
super.initState();
getMetadataList();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (widget.attachmentsId.isEmpty) { if (widget.attachmentsId.isEmpty) {
@ -236,7 +230,8 @@ class _AttachmentListState extends State<AttachmentList> {
const radius = BorderRadius.all(Radius.circular(16)); const radius = BorderRadius.all(Radius.circular(16));
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: Theme.of(context).dividerColor, width: 1), border:
Border.all(color: Theme.of(context).dividerColor, width: 1),
borderRadius: radius, borderRadius: radius,
), ),
child: ClipRRect( child: ClipRRect(

View File

@ -1,6 +1,10 @@
import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:isolate';
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_animate/flutter_animate.dart';
@ -10,6 +14,7 @@ import 'package:solian/exts.dart';
import 'package:solian/models/attachment.dart'; import 'package:solian/models/attachment.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/providers/content/attachment.dart'; import 'package:solian/providers/content/attachment.dart';
import 'package:super_drag_and_drop/super_drag_and_drop.dart';
class AttachmentPublishPopup extends StatefulWidget { class AttachmentPublishPopup extends StatefulWidget {
final String usage; final String usage;
@ -24,8 +29,7 @@ class AttachmentPublishPopup extends StatefulWidget {
}); });
@override @override
State<AttachmentPublishPopup> createState() => State<AttachmentPublishPopup> createState() => _AttachmentPublishPopupState();
_AttachmentPublishPopupState();
} }
class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> { class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
@ -51,7 +55,8 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
try { try {
await uploadAttachment( await uploadAttachment(
file, await file.readAsBytes(),
file.path,
hash, hash,
ratio: await calculateFileAspectRatio(file), ratio: await calculateFileAspectRatio(file),
); );
@ -77,7 +82,8 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
const ratio = 16 / 9; const ratio = 16 / 9;
try { try {
await uploadAttachment(file, hash, ratio: ratio); await uploadAttachment(await file.readAsBytes(), file.path, hash,
ratio: ratio);
} catch (err) { } catch (err) {
context.showErrorDialog(err); context.showErrorDialog(err);
} }
@ -100,7 +106,7 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
for (final file in files) { for (final file in files) {
final hash = await calculateFileSha256(file); final hash = await calculateFileSha256(file);
try { try {
await uploadAttachment(file, hash); await uploadAttachment(await file.readAsBytes(), file.path, hash);
} catch (err) { } catch (err) {
context.showErrorDialog(err); context.showErrorDialog(err);
} }
@ -134,7 +140,12 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
} }
try { try {
await uploadAttachment(file, hash, ratio: ratio); await uploadAttachment(
await file.readAsBytes(),
file.path,
hash,
ratio: ratio,
);
} catch (err) { } catch (err) {
context.showErrorDialog(err); context.showErrorDialog(err);
} }
@ -142,11 +153,13 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
setState(() => _isBusy = false); setState(() => _isBusy = false);
} }
Future<void> uploadAttachment(File file, String hash, {double? ratio}) async { Future<void> uploadAttachment(Uint8List data, String path, String hash,
{double? ratio}) async {
final AttachmentProvider provider = Get.find(); final AttachmentProvider provider = Get.find();
try { try {
final resp = await provider.createAttachment( final resp = await provider.createAttachment(
file, data,
path,
hash, hash,
widget.usage, widget.usage,
ratio: ratio, ratio: ratio,
@ -208,10 +221,14 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
revertMetadataList(); revertMetadataList();
} }
@override
void dispose() {
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
const density = VisualDensity(horizontal: 0, vertical: 0); const density = VisualDensity(horizontal: 0, vertical: 0);
@ -219,134 +236,165 @@ class _AttachmentPublishPopupState extends State<AttachmentPublishPopup> {
return SafeArea( return SafeArea(
child: SizedBox( child: SizedBox(
height: MediaQuery.of(context).size.height * 0.85, height: MediaQuery.of(context).size.height * 0.85,
child: Column( child: DropRegion(
crossAxisAlignment: CrossAxisAlignment.start, formats: Formats.standardFormats,
children: [ hitTestBehavior: HitTestBehavior.opaque,
Text( onDropOver: (event) {
'attachmentAdd'.tr, if (event.session.allowedOperations.contains(DropOperation.copy)) {
style: Theme.of(context).textTheme.headlineSmall, return DropOperation.copy;
).paddingOnly(left: 24, right: 24, top: 32, bottom: 16), } else {
if (_isBusy) const LinearProgressIndicator().animate().scaleX(), return DropOperation.none;
Expanded( }
child: Builder(builder: (context) { },
if (_isFirstTimeBusy && _isBusy) { onPerformDrop: (event) async {
return const Center( for (final item in event.session.items) {
child: CircularProgressIndicator(), final reader = item.dataReader!;
); for (final format
} in Formats.standardFormats.whereType<FileFormat>()) {
if (reader.canProvide(format)) {
return ListView.builder( reader.getFile(format, (file) async {
itemCount: _attachments.length, final data = await file.readAll();
itemBuilder: (context, index) { await uploadAttachment(
final element = _attachments[index]; data,
var fileType = element!.mimetype.split('/').firstOrNull; file.fileName ?? 'attachment',
fileType ??= 'unknown'; await calculateBytesSha256(data),
return Container(
padding:
const EdgeInsets.only(left: 16, right: 8, bottom: 16),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
element.alt,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: const TextStyle(
fontWeight: FontWeight.bold),
),
Text(
'${fileType[0].toUpperCase()}${fileType.substring(1)} · ${formatBytes(element.size)}',
),
],
),
),
IconButton(
style: TextButton.styleFrom(
shape: const CircleBorder(),
foregroundColor: Theme.of(context).primaryColor,
),
icon: const Icon(Icons.more_horiz),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AttachmentEditorDialog(
item: element,
onDelete: () {
setState(
() => _attachments.removeAt(index));
widget.onUpdate(_attachments
.map((e) => e!.id)
.toList());
},
onUpdate: (item) {
setState(
() => _attachments[index] = item);
widget.onUpdate(_attachments
.map((e) => e!.id)
.toList());
},
);
},
);
},
),
],
),
); );
}, }, onError: (error) {
); print('Error reading value $error');
}), });
), }
const Divider(thickness: 0.3, height: 0.3), }
SizedBox( }
height: 64, },
child: SingleChildScrollView( child: Column(
scrollDirection: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.start,
child: Wrap( children: [
spacing: 8, Text(
runSpacing: 0, 'attachmentAdd'.tr,
alignment: WrapAlignment.center, style: Theme.of(context).textTheme.headlineSmall,
runAlignment: WrapAlignment.center, ).paddingOnly(left: 24, right: 24, top: 32, bottom: 16),
children: [ if (_isBusy) const LinearProgressIndicator().animate().scaleX(),
ElevatedButton.icon( Expanded(
icon: const Icon(Icons.add_photo_alternate), child: Builder(builder: (context) {
label: Text('attachmentAddGalleryPhoto'.tr), if (_isFirstTimeBusy && _isBusy) {
style: const ButtonStyle(visualDensity: density), return const Center(
onPressed: () => pickPhotoToUpload(), child: CircularProgressIndicator(),
), );
ElevatedButton.icon( }
icon: const Icon(Icons.add_road),
label: Text('attachmentAddGalleryVideo'.tr), return ListView.builder(
style: const ButtonStyle(visualDensity: density), itemCount: _attachments.length,
onPressed: () => pickVideoToUpload(), itemBuilder: (context, index) {
), final element = _attachments[index];
ElevatedButton.icon( var fileType = element!.mimetype.split('/').firstOrNull;
icon: const Icon(Icons.photo_camera_back), fileType ??= 'unknown';
label: Text('attachmentAddCameraPhoto'.tr), return Container(
style: const ButtonStyle(visualDensity: density), padding: const EdgeInsets.only(
onPressed: () => takeMediaToUpload(false), left: 16, right: 8, bottom: 16),
), child: Row(
ElevatedButton.icon( children: [
icon: const Icon(Icons.video_camera_back_outlined), Expanded(
label: Text('attachmentAddCameraVideo'.tr), child: Column(
style: const ButtonStyle(visualDensity: density), crossAxisAlignment: CrossAxisAlignment.start,
onPressed: () => takeMediaToUpload(true), children: [
), Text(
ElevatedButton.icon( element.alt,
icon: const Icon(Icons.file_present_rounded), overflow: TextOverflow.ellipsis,
label: Text('attachmentAddFile'.tr), maxLines: 1,
style: const ButtonStyle(visualDensity: density), style: const TextStyle(
onPressed: () => pickFileToUpload(), fontWeight: FontWeight.bold),
), ),
], Text(
).paddingSymmetric(horizontal: 12), '${fileType[0].toUpperCase()}${fileType.substring(1)} · ${formatBytes(element.size)}',
),
],
),
),
IconButton(
style: TextButton.styleFrom(
shape: const CircleBorder(),
foregroundColor: Theme.of(context).primaryColor,
),
icon: const Icon(Icons.more_horiz),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AttachmentEditorDialog(
item: element,
onDelete: () {
setState(
() => _attachments.removeAt(index));
widget.onUpdate(_attachments
.map((e) => e!.id)
.toList());
},
onUpdate: (item) {
setState(
() => _attachments[index] = item);
widget.onUpdate(_attachments
.map((e) => e!.id)
.toList());
},
);
},
);
},
),
],
),
);
},
);
}),
), ),
) const Divider(thickness: 0.3, height: 0.3),
], SizedBox(
height: 64,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Wrap(
spacing: 8,
runSpacing: 0,
alignment: WrapAlignment.center,
runAlignment: WrapAlignment.center,
children: [
ElevatedButton.icon(
icon: const Icon(Icons.add_photo_alternate),
label: Text('attachmentAddGalleryPhoto'.tr),
style: const ButtonStyle(visualDensity: density),
onPressed: () => pickPhotoToUpload(),
),
ElevatedButton.icon(
icon: const Icon(Icons.add_road),
label: Text('attachmentAddGalleryVideo'.tr),
style: const ButtonStyle(visualDensity: density),
onPressed: () => pickVideoToUpload(),
),
ElevatedButton.icon(
icon: const Icon(Icons.photo_camera_back),
label: Text('attachmentAddCameraPhoto'.tr),
style: const ButtonStyle(visualDensity: density),
onPressed: () => takeMediaToUpload(false),
),
ElevatedButton.icon(
icon: const Icon(Icons.video_camera_back_outlined),
label: Text('attachmentAddCameraVideo'.tr),
style: const ButtonStyle(visualDensity: density),
onPressed: () => takeMediaToUpload(true),
),
ElevatedButton.icon(
icon: const Icon(Icons.file_present_rounded),
label: Text('attachmentAddFile'.tr),
style: const ButtonStyle(visualDensity: density),
onPressed: () => pickFileToUpload(),
),
],
).paddingSymmetric(horizontal: 12),
),
)
],
),
), ),
), ),
); );
@ -365,8 +413,7 @@ class AttachmentEditorDialog extends StatefulWidget {
required this.onUpdate}); required this.onUpdate});
@override @override
State<AttachmentEditorDialog> createState() => State<AttachmentEditorDialog> createState() => _AttachmentEditorDialogState();
_AttachmentEditorDialogState();
} }
class _AttachmentEditorDialogState extends State<AttachmentEditorDialog> { class _AttachmentEditorDialogState extends State<AttachmentEditorDialog> {

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:solian/controllers/chat_events_controller.dart'; import 'package:solian/controllers/chat_events_controller.dart';

View File

@ -10,7 +10,9 @@
#include <flutter_acrylic/flutter_acrylic_plugin.h> #include <flutter_acrylic/flutter_acrylic_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h> #include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h> #include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
#include <irondash_engine_context/irondash_engine_context_plugin.h>
#include <sentry_flutter/sentry_flutter_plugin.h> #include <sentry_flutter/sentry_flutter_plugin.h>
#include <super_native_extensions/super_native_extensions_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
@ -26,9 +28,15 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_webrtc_registrar = g_autoptr(FlPluginRegistrar) flutter_webrtc_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterWebRTCPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterWebRTCPlugin");
flutter_web_r_t_c_plugin_register_with_registrar(flutter_webrtc_registrar); flutter_web_r_t_c_plugin_register_with_registrar(flutter_webrtc_registrar);
g_autoptr(FlPluginRegistrar) irondash_engine_context_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "IrondashEngineContextPlugin");
irondash_engine_context_plugin_register_with_registrar(irondash_engine_context_registrar);
g_autoptr(FlPluginRegistrar) sentry_flutter_registrar = g_autoptr(FlPluginRegistrar) sentry_flutter_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "SentryFlutterPlugin");
sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar); sentry_flutter_plugin_register_with_registrar(sentry_flutter_registrar);
g_autoptr(FlPluginRegistrar) super_native_extensions_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SuperNativeExtensionsPlugin");
super_native_extensions_plugin_register_with_registrar(super_native_extensions_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -7,7 +7,9 @@ list(APPEND FLUTTER_PLUGIN_LIST
flutter_acrylic flutter_acrylic
flutter_secure_storage_linux flutter_secure_storage_linux
flutter_webrtc flutter_webrtc
irondash_engine_context
sentry_flutter sentry_flutter
super_native_extensions
url_launcher_linux url_launcher_linux
) )

View File

@ -13,6 +13,7 @@ import firebase_messaging
import flutter_local_notifications import flutter_local_notifications
import flutter_secure_storage_macos import flutter_secure_storage_macos
import flutter_webrtc import flutter_webrtc
import irondash_engine_context
import livekit_client import livekit_client
import macos_window_utils import macos_window_utils
import package_info_plus import package_info_plus
@ -21,6 +22,7 @@ import protocol_handler_macos
import sentry_flutter import sentry_flutter
import shared_preferences_foundation import shared_preferences_foundation
import sqflite import sqflite
import super_native_extensions
import url_launcher_macos import url_launcher_macos
import video_player_avfoundation import video_player_avfoundation
import wakelock_plus import wakelock_plus
@ -34,6 +36,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin")) FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin"))
IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin"))
LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin")) LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin"))
MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin")) MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
@ -42,6 +45,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin")) SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
SuperNativeExtensionsPlugin.register(with: registry.registrar(forPlugin: "SuperNativeExtensionsPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))

View File

@ -824,6 +824,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
irondash_engine_context:
dependency: transitive
description:
name: irondash_engine_context
sha256: cd7b769db11a2b5243b037c8a9b1ecaef02e1ae27a2d909ffa78c1dad747bb10
url: "https://pub.dev"
source: hosted
version: "0.5.4"
irondash_message_channel:
dependency: transitive
description:
name: irondash_message_channel
sha256: b4101669776509c76133b8917ab8cfc704d3ad92a8c450b92934dd8884a2f060
url: "https://pub.dev"
source: hosted
version: "0.7.0"
js: js:
dependency: transitive dependency: transitive
description: description:
@ -1104,6 +1120,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.2" version: "6.0.2"
pixel_snap:
dependency: transitive
description:
name: pixel_snap
sha256: "677410ea37b07cd37ecb6d5e6c0d8d7615a7cf3bd92ba406fd1ac57e937d1fb0"
url: "https://pub.dev"
source: hosted
version: "0.1.5"
platform: platform:
dependency: transitive dependency: transitive
description: description:
@ -1453,6 +1477,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
super_clipboard:
dependency: transitive
description:
name: super_clipboard
sha256: cdab725bac26655ebd189f4d202d694a8cbc1c21e0f0478ccd7829c71716f09b
url: "https://pub.dev"
source: hosted
version: "0.8.17"
super_drag_and_drop:
dependency: "direct main"
description:
name: super_drag_and_drop
sha256: "8e00c6082646076f80b972b39d9c27b5311082ea1e8add5fa370ce11c410f7de"
url: "https://pub.dev"
source: hosted
version: "0.8.17"
super_native_extensions:
dependency: transitive
description:
name: super_native_extensions
sha256: fa55d452d34b7112453afbb9fa4d13c0527ff201630d10d86546497179030544
url: "https://pub.dev"
source: hosted
version: "0.8.17"
synchronized: synchronized:
dependency: transitive dependency: transitive
description: description:

View File

@ -51,6 +51,7 @@ dependencies:
sqflite: ^2.3.3+1 sqflite: ^2.3.3+1
protocol_handler: ^0.2.0 protocol_handler: ^0.2.0
markdown: ^7.2.2 markdown: ^7.2.2
super_drag_and_drop: ^0.8.17
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -12,10 +12,12 @@
#include <flutter_acrylic/flutter_acrylic_plugin.h> #include <flutter_acrylic/flutter_acrylic_plugin.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h> #include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <flutter_webrtc/flutter_web_r_t_c_plugin.h> #include <flutter_webrtc/flutter_web_r_t_c_plugin.h>
#include <irondash_engine_context/irondash_engine_context_plugin_c_api.h>
#include <livekit_client/live_kit_plugin.h> #include <livekit_client/live_kit_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h> #include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <protocol_handler_windows/protocol_handler_windows_plugin_c_api.h> #include <protocol_handler_windows/protocol_handler_windows_plugin_c_api.h>
#include <sentry_flutter/sentry_flutter_plugin.h> #include <sentry_flutter/sentry_flutter_plugin.h>
#include <super_native_extensions/super_native_extensions_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
#include <video_player_win/video_player_win_plugin_c_api.h> #include <video_player_win/video_player_win_plugin_c_api.h>
@ -32,6 +34,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
FlutterWebRTCPluginRegisterWithRegistrar( FlutterWebRTCPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterWebRTCPlugin")); registry->GetRegistrarForPlugin("FlutterWebRTCPlugin"));
IrondashEngineContextPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi"));
LiveKitPluginRegisterWithRegistrar( LiveKitPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("LiveKitPlugin")); registry->GetRegistrarForPlugin("LiveKitPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar( PermissionHandlerWindowsPluginRegisterWithRegistrar(
@ -40,6 +44,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("ProtocolHandlerWindowsPluginCApi")); registry->GetRegistrarForPlugin("ProtocolHandlerWindowsPluginCApi"));
SentryFlutterPluginRegisterWithRegistrar( SentryFlutterPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SentryFlutterPlugin")); registry->GetRegistrarForPlugin("SentryFlutterPlugin"));
SuperNativeExtensionsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SuperNativeExtensionsPluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar( UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows")); registry->GetRegistrarForPlugin("UrlLauncherWindows"));
VideoPlayerWinPluginCApiRegisterWithRegistrar( VideoPlayerWinPluginCApiRegisterWithRegistrar(

View File

@ -9,10 +9,12 @@ list(APPEND FLUTTER_PLUGIN_LIST
flutter_acrylic flutter_acrylic
flutter_secure_storage_windows flutter_secure_storage_windows
flutter_webrtc flutter_webrtc
irondash_engine_context
livekit_client livekit_client
permission_handler_windows permission_handler_windows
protocol_handler_windows protocol_handler_windows
sentry_flutter sentry_flutter
super_native_extensions
url_launcher_windows url_launcher_windows
video_player_win video_player_win
) )