:drunk: I have no idea what did I did
This commit is contained in:
parent
9aca6eb674
commit
33e84805d7
83
.github/workflows/build.yml
vendored
Normal file
83
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
name: Build Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-web:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: stable
|
||||
cache: true
|
||||
- run: flutter pub get
|
||||
- run: flutter build web --release
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-output-web
|
||||
path: build/web
|
||||
build-exe:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: stable
|
||||
cache: true
|
||||
- run: flutter pub get
|
||||
- run: flutter build windows
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-output-windows
|
||||
path: build/windows/x64/runner/Release
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: stable
|
||||
- run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y ninja-build libgtk-3-dev
|
||||
sudo apt-get install -y libmpv-dev mpv
|
||||
sudo apt-get install -y libayatana-appindicator3-dev
|
||||
sudo apt-get install -y keybinder-3.0
|
||||
sudo apt-get install -y libnotify-dev
|
||||
sudo apt-get install -y libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
|
||||
sudo apt-get install -y gstreamer-1.0
|
||||
- run: flutter pub get
|
||||
- run: flutter build linux
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-output-linux
|
||||
path: build/linux/x64/release/bundle
|
||||
- name: Build AppImage
|
||||
run: |
|
||||
rm -r Solian.AppDir | true
|
||||
mkdir Solian.AppDir
|
||||
cp -r build/linux/x64/release/bundle/* Solian.AppDir
|
||||
cp -r buildtools/appimage_config/* Solian.AppDir
|
||||
cp assets/icon/icon-light-radius.png Solian.AppDir
|
||||
sudo chmod +x buildtools/appimagetool-x86_64.AppImage
|
||||
sudo chmod +x Solian.AppDir/AppRun
|
||||
./buildtools/appimagetool-x86_64.AppImage Solian.AppDir
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-output-linux-appimage
|
||||
path: './*.AppImage*'
|
@ -325,5 +325,10 @@
|
||||
"accountSettingsHelpContent": "This page allows you to manage your account security, privacy, and other settings. If you need assistance, please contact support.",
|
||||
"unauthorized": "Unauthorized",
|
||||
"unauthorizedHint": "You're not signed in or session expired, please sign in again.",
|
||||
"publisherVisitAccountPage": "Visit the profile of {}"
|
||||
"publisherVisitAccountPage": "Visit the profile of {}",
|
||||
"postVisibility": "Visibility",
|
||||
"postVisibilityPublic": "Public",
|
||||
"postVisibilityFriends": "Friends Only",
|
||||
"postVisibilityUnlisted": "Unlisted",
|
||||
"postVisibilityPrivate": "Private"
|
||||
}
|
||||
|
@ -286,5 +286,10 @@
|
||||
"settingsHideBottomNav": "隐藏底部导航",
|
||||
"settingsSoundEffects": "音效",
|
||||
"settingsAprilFoolFeatures": "愚人节功能",
|
||||
"settingsEnterToSend": "按下 Enter 发送"
|
||||
"settingsEnterToSend": "按下 Enter 发送",
|
||||
"postVisibility": "可见性",
|
||||
"postVisibilityPublic": "公开",
|
||||
"postVisibilityFriends": "仅好友可见",
|
||||
"postVisibilityUnlisted": "不公开",
|
||||
"postVisibilityPrivate": "私密"
|
||||
}
|
@ -286,5 +286,10 @@
|
||||
"settingsHideBottomNav": "隱藏底部導航",
|
||||
"settingsSoundEffects": "音效",
|
||||
"settingsAprilFoolFeatures": "愚人節功能",
|
||||
"settingsEnterToSend": "按下 Enter 傳送"
|
||||
"settingsEnterToSend": "按下 Enter 傳送",
|
||||
"postVisibility": "可見性",
|
||||
"postVisibilityPublic": "公開",
|
||||
"postVisibilityFriends": "僅好友可見",
|
||||
"postVisibilityUnlisted": "不公開",
|
||||
"postVisibilityPrivate": "私密"
|
||||
}
|
@ -1071,10 +1071,17 @@ class PostComposeRoute extends _i27.PageRouteInfo<PostComposeRouteArgs> {
|
||||
PostComposeRoute({
|
||||
_i28.Key? key,
|
||||
_i30.SnPost? originalPost,
|
||||
_i30.SnPost? repliedPost,
|
||||
_i30.SnPost? forwardedPost,
|
||||
List<_i27.PageRouteInfo>? children,
|
||||
}) : super(
|
||||
PostComposeRoute.name,
|
||||
args: PostComposeRouteArgs(key: key, originalPost: originalPost),
|
||||
args: PostComposeRouteArgs(
|
||||
key: key,
|
||||
originalPost: originalPost,
|
||||
repliedPost: repliedPost,
|
||||
forwardedPost: forwardedPost,
|
||||
),
|
||||
initialChildren: children,
|
||||
);
|
||||
|
||||
@ -1089,32 +1096,50 @@ class PostComposeRoute extends _i27.PageRouteInfo<PostComposeRouteArgs> {
|
||||
return _i18.PostComposeScreen(
|
||||
key: args.key,
|
||||
originalPost: args.originalPost,
|
||||
repliedPost: args.repliedPost,
|
||||
forwardedPost: args.forwardedPost,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class PostComposeRouteArgs {
|
||||
const PostComposeRouteArgs({this.key, this.originalPost});
|
||||
const PostComposeRouteArgs({
|
||||
this.key,
|
||||
this.originalPost,
|
||||
this.repliedPost,
|
||||
this.forwardedPost,
|
||||
});
|
||||
|
||||
final _i28.Key? key;
|
||||
|
||||
final _i30.SnPost? originalPost;
|
||||
|
||||
final _i30.SnPost? repliedPost;
|
||||
|
||||
final _i30.SnPost? forwardedPost;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PostComposeRouteArgs{key: $key, originalPost: $originalPost}';
|
||||
return 'PostComposeRouteArgs{key: $key, originalPost: $originalPost, repliedPost: $repliedPost, forwardedPost: $forwardedPost}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! PostComposeRouteArgs) return false;
|
||||
return key == other.key && originalPost == other.originalPost;
|
||||
return key == other.key &&
|
||||
originalPost == other.originalPost &&
|
||||
repliedPost == other.repliedPost &&
|
||||
forwardedPost == other.forwardedPost;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => key.hashCode ^ originalPost.hashCode;
|
||||
int get hashCode =>
|
||||
key.hashCode ^
|
||||
originalPost.hashCode ^
|
||||
repliedPost.hashCode ^
|
||||
forwardedPost.hashCode;
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
|
@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
@ -63,7 +64,10 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
if (token == null) throw ArgumentError('Token is null');
|
||||
final cloudFile =
|
||||
await putMediaToCloud(
|
||||
fileData: result,
|
||||
fileData: UniversalFile(
|
||||
data: result,
|
||||
type: UniversalFileType.image,
|
||||
),
|
||||
atk: token,
|
||||
baseUrl: baseUrl,
|
||||
filename: result.name,
|
||||
|
@ -527,7 +527,10 @@ class EditChatScreen extends HookConsumerWidget {
|
||||
if (token == null) throw ArgumentError('Token is null');
|
||||
final cloudFile =
|
||||
await putMediaToCloud(
|
||||
fileData: result,
|
||||
fileData: UniversalFile(
|
||||
data: result,
|
||||
type: UniversalFileType.image,
|
||||
),
|
||||
atk: token,
|
||||
baseUrl: baseUrl,
|
||||
filename: result.name,
|
||||
|
@ -17,12 +17,12 @@ import 'package:island/pods/database.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/websocket.dart';
|
||||
import 'package:island/route.gr.dart';
|
||||
import 'package:island/screens/posts/compose.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/chat/call_overlay.dart';
|
||||
import 'package:island/widgets/chat/message_item.dart';
|
||||
import 'package:island/widgets/content/attachment_preview.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
@ -514,7 +514,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
),
|
||||
loading: () => const Text('Loading...'),
|
||||
error:
|
||||
(err, __) => ResponseErrorWidget(
|
||||
(err, _) => ResponseErrorWidget(
|
||||
error: err,
|
||||
onRetry: () => messagesNotifier.loadInitial(),
|
||||
),
|
||||
@ -615,7 +615,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
progress: null,
|
||||
showAvatar: false,
|
||||
),
|
||||
error: (_, __) => const SizedBox.shrink(),
|
||||
error: (_, _) => const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -680,7 +680,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
||||
attachments.value = newAttachments;
|
||||
},
|
||||
),
|
||||
error: (_, __) => const SizedBox.shrink(),
|
||||
error: (_, _) => const SizedBox.shrink(),
|
||||
loading: () => const SizedBox.shrink(),
|
||||
),
|
||||
],
|
||||
@ -788,7 +788,7 @@ class _ChatInput extends ConsumerWidget {
|
||||
onMove: (delta) => onMoveAttachment(idx, delta),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, __) => const Gap(8),
|
||||
separatorBuilder: (_, _) => const Gap(8),
|
||||
),
|
||||
).padding(top: 12),
|
||||
if (messageReplyingTo != null ||
|
||||
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/models/realm.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
@ -99,7 +100,10 @@ class EditPublisherScreen extends HookConsumerWidget {
|
||||
if (token == null) throw ArgumentError('Token is null');
|
||||
final cloudFile =
|
||||
await putMediaToCloud(
|
||||
fileData: result,
|
||||
fileData: UniversalFile(
|
||||
data: result,
|
||||
type: UniversalFileType.image,
|
||||
),
|
||||
atk: token,
|
||||
baseUrl: baseUrl,
|
||||
filename: result.name,
|
||||
|
@ -1,5 +1,3 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
@ -21,6 +19,7 @@ import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/attachment_preview.dart';
|
||||
import 'package:island/widgets/post/publishers_modal.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:pasteboard/pasteboard.dart';
|
||||
@ -53,7 +52,14 @@ class PostEditScreen extends HookConsumerWidget {
|
||||
@RoutePage()
|
||||
class PostComposeScreen extends HookConsumerWidget {
|
||||
final SnPost? originalPost;
|
||||
const PostComposeScreen({super.key, this.originalPost});
|
||||
final SnPost? repliedPost;
|
||||
final SnPost? forwardedPost;
|
||||
const PostComposeScreen({
|
||||
super.key,
|
||||
this.originalPost,
|
||||
this.repliedPost,
|
||||
this.forwardedPost,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@ -90,9 +96,14 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
text: originalPost?.description,
|
||||
);
|
||||
final contentController = useTextEditingController(
|
||||
text: originalPost?.content,
|
||||
text:
|
||||
originalPost?.content ??
|
||||
(forwardedPost != null ? '> ${forwardedPost!.content}\n\n' : null),
|
||||
);
|
||||
|
||||
// Add visibility state with default value from original post or 0 (public)
|
||||
final visibility = useState<int>(originalPost?.visibility ?? 0);
|
||||
|
||||
final submitting = useState(false);
|
||||
|
||||
Future<void> pickPhotoMedia() async {
|
||||
@ -188,12 +199,18 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
await client.request(
|
||||
originalPost == null ? '/posts' : '/posts/${originalPost!.id}',
|
||||
data: {
|
||||
'title': titleController.text,
|
||||
'description': descriptionController.text,
|
||||
'content': contentController.text,
|
||||
'visibility':
|
||||
visibility.value, // Add visibility field to API request
|
||||
'attachments':
|
||||
attachments.value
|
||||
.where((e) => e.isOnCloud)
|
||||
.map((e) => e.data.id)
|
||||
.toList(),
|
||||
if (repliedPost != null) 'replied_post_id': repliedPost!.id,
|
||||
if (forwardedPost != null) 'forwarded_post_id': forwardedPost!.id,
|
||||
},
|
||||
options: Options(
|
||||
headers: {'X-Pub': currentPublisher.value?.name},
|
||||
@ -210,7 +227,7 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handlePaste() async {
|
||||
Future<void> handlePaste() async {
|
||||
final clipboard = await Pasteboard.image;
|
||||
if (clipboard == null) return;
|
||||
|
||||
@ -223,14 +240,93 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
];
|
||||
}
|
||||
|
||||
void _handleKeyPress(RawKeyEvent event) {
|
||||
void handleKeyPress(RawKeyEvent event) {
|
||||
if (event is! RawKeyDownEvent) return;
|
||||
|
||||
final isPaste = event.logicalKey == LogicalKeyboardKey.keyV;
|
||||
final isModifierPressed = event.isMetaPressed || event.isControlPressed;
|
||||
|
||||
if (isPaste && isModifierPressed) {
|
||||
_handlePaste();
|
||||
handlePaste();
|
||||
}
|
||||
}
|
||||
|
||||
void showVisibilityModal() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(context) => AlertDialog(
|
||||
title: Text('postVisibility'.tr()),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
leading: Icon(Symbols.public),
|
||||
title: Text('postVisibilityPublic'.tr()),
|
||||
onTap: () {
|
||||
visibility.value = 0;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
selected: visibility.value == 0,
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Symbols.group),
|
||||
title: Text('postVisibilityFriends'.tr()),
|
||||
onTap: () {
|
||||
visibility.value = 1;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
selected: visibility.value == 1,
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Symbols.link_off),
|
||||
title: Text('postVisibilityUnlisted'.tr()),
|
||||
onTap: () {
|
||||
visibility.value = 2;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
selected: visibility.value == 2,
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(Symbols.lock),
|
||||
title: Text('postVisibilityPrivate'.tr()),
|
||||
onTap: () {
|
||||
visibility.value = 3;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
selected: visibility.value == 3,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Helper method to get the appropriate icon for each visibility status
|
||||
IconData getVisibilityIcon(int visibilityValue) {
|
||||
switch (visibilityValue) {
|
||||
case 1: // Friends
|
||||
return Symbols.group;
|
||||
case 2: // Unlisted
|
||||
return Symbols.link_off;
|
||||
case 3: // Private
|
||||
return Symbols.lock;
|
||||
default: // Public (0) or unknown
|
||||
return Symbols.public;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to get the translation key for each visibility status
|
||||
String getVisibilityText(int visibilityValue) {
|
||||
switch (visibilityValue) {
|
||||
case 1: // Friends
|
||||
return 'postVisibilityFriends';
|
||||
case 2: // Unlisted
|
||||
return 'postVisibilityUnlisted';
|
||||
case 3: // Private
|
||||
return 'postVisibilityPrivate';
|
||||
default: // Public (0) or unknown
|
||||
return 'postVisibilityPublic';
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,6 +392,48 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (repliedPost != null)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceVariant.withOpacity(0.5),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Symbols.reply, size: 16),
|
||||
const Gap(8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${'reply'.tr()}: ${repliedPost!.publisher.nick}',
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (forwardedPost != null)
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.surfaceVariant.withOpacity(0.5),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Symbols.forward, size: 16),
|
||||
const Gap(8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${'forward'.tr()}: ${forwardedPost!.publisher.nick}',
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Row(
|
||||
spacing: 12,
|
||||
@ -324,7 +462,52 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
OutlinedButton(
|
||||
onPressed: () {
|
||||
showVisibilityModal();
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
side: BorderSide(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary.withOpacity(0.5),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
visualDensity: const VisualDensity(
|
||||
vertical: -2,
|
||||
horizontal: -4,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
getVisibilityIcon(visibility.value),
|
||||
size: 16,
|
||||
color:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
getVisibilityText(visibility.value).tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(bottom: 6),
|
||||
TextField(
|
||||
controller: titleController,
|
||||
decoration: InputDecoration.collapsed(
|
||||
@ -348,7 +531,7 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
const Gap(8),
|
||||
RawKeyboardListener(
|
||||
focusNode: FocusNode(),
|
||||
onKey: _handleKeyPress,
|
||||
onKey: handleKeyPress,
|
||||
child: TextField(
|
||||
controller: contentController,
|
||||
style: TextStyle(fontSize: 14),
|
||||
@ -474,204 +657,3 @@ class PostComposeScreen extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AttachmentPreview extends StatelessWidget {
|
||||
final UniversalFile item;
|
||||
final double? progress;
|
||||
final Function(int)? onMove;
|
||||
final Function? onDelete;
|
||||
final Function? onRequestUpload;
|
||||
const AttachmentPreview({
|
||||
super.key,
|
||||
required this.item,
|
||||
this.progress,
|
||||
this.onRequestUpload,
|
||||
this.onMove,
|
||||
this.onDelete,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AspectRatio(
|
||||
aspectRatio:
|
||||
(item.isOnCloud ? (item.data.fileMeta?['ratio'] ?? 1) : 1).toDouble(),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
if (item.isOnCloud) {
|
||||
return CloudFileWidget(item: item.data);
|
||||
} else if (item.data is XFile) {
|
||||
if (item.type == UniversalFileType.image) {
|
||||
return Image.file(File(item.data.path));
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Preview is not supported for ${item.type}',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if (item is List<int> || item is Uint8List) {
|
||||
if (item.type == UniversalFileType.image) {
|
||||
return Image.memory(item.data);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Preview is not supported for ${item.type}',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return Placeholder();
|
||||
},
|
||||
),
|
||||
),
|
||||
if (progress != null)
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (progress != null)
|
||||
Text(
|
||||
'${progress!.toStringAsFixed(2)}%',
|
||||
style: TextStyle(color: Colors.white),
|
||||
)
|
||||
else
|
||||
Text(
|
||||
'uploading'.tr(),
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
Gap(6),
|
||||
Center(child: LinearProgressIndicator(value: progress)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 8,
|
||||
top: 8,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (onDelete != null)
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Icon(
|
||||
Symbols.delete,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
).padding(horizontal: 8, vertical: 6),
|
||||
onTap: () {
|
||||
onDelete?.call();
|
||||
},
|
||||
),
|
||||
if (onDelete != null && onMove != null)
|
||||
SizedBox(
|
||||
height: 26,
|
||||
child: const VerticalDivider(
|
||||
width: 0.3,
|
||||
color: Colors.white,
|
||||
thickness: 0.3,
|
||||
),
|
||||
).padding(horizontal: 2),
|
||||
if (onMove != null)
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Icon(
|
||||
Symbols.keyboard_arrow_up,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
).padding(horizontal: 8, vertical: 6),
|
||||
onTap: () {
|
||||
onMove?.call(-1);
|
||||
},
|
||||
),
|
||||
if (onMove != null)
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Icon(
|
||||
Symbols.keyboard_arrow_down,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
).padding(horizontal: 8, vertical: 6),
|
||||
onTap: () {
|
||||
onMove?.call(1);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (onRequestUpload != null)
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
onTap: () => onRequestUpload?.call(),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child:
|
||||
(item.isOnCloud)
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.cloud,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'On-cloud',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.cloud_off,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'On-device',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import 'package:auto_route/annotations.dart';
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -215,7 +215,10 @@ class EditRealmScreen extends HookConsumerWidget {
|
||||
if (token == null) throw ArgumentError('Access token is null');
|
||||
final cloudFile =
|
||||
await putMediaToCloud(
|
||||
fileData: result,
|
||||
fileData: UniversalFile(
|
||||
data: result,
|
||||
type: UniversalFileType.image,
|
||||
),
|
||||
atk: token,
|
||||
baseUrl: baseUrl,
|
||||
filename: result.name,
|
||||
|
@ -39,7 +39,7 @@ Future<XFile?> cropImage(
|
||||
}
|
||||
|
||||
Completer<SnCloudFile?> putMediaToCloud({
|
||||
required dynamic fileData, // Can be XFile or List<int> (Uint8List)
|
||||
required UniversalFile fileData,
|
||||
required String atk,
|
||||
required String baseUrl,
|
||||
String? filename,
|
||||
@ -51,21 +51,27 @@ Completer<SnCloudFile?> putMediaToCloud({
|
||||
String actualMimetype = mimetype ?? '';
|
||||
Uint8List? byteData;
|
||||
|
||||
if (fileData is XFile) {
|
||||
file = fileData;
|
||||
actualFilename = filename ?? fileData.name;
|
||||
actualMimetype = mimetype ?? fileData.mimeType ?? '';
|
||||
} else if (fileData is List<int> || fileData is Uint8List) {
|
||||
byteData = fileData is List<int> ? Uint8List.fromList(fileData) : fileData;
|
||||
// Handle the data based on what's in the UniversalFile
|
||||
final data = fileData.data;
|
||||
|
||||
if (data is XFile) {
|
||||
file = data;
|
||||
actualFilename = filename ?? data.name;
|
||||
actualMimetype = mimetype ?? data.mimeType ?? '';
|
||||
} else if (data is List<int> || data is Uint8List) {
|
||||
byteData = data is List<int> ? Uint8List.fromList(data) : data;
|
||||
actualFilename = filename ?? 'uploaded_file';
|
||||
actualMimetype = mimetype ?? 'application/octet-stream';
|
||||
if (mimetype == null) {
|
||||
throw ArgumentError('Mimetype is required when providing raw bytes.');
|
||||
}
|
||||
file = XFile.fromData(byteData!, mimeType: actualMimetype);
|
||||
} else if (data is SnCloudFile) {
|
||||
// If the file is already on the cloud, just return it
|
||||
return Completer<SnCloudFile?>()..complete(data);
|
||||
} else {
|
||||
throw ArgumentError(
|
||||
'Invalid fileData type. Expected XFile or List<int> (Uint8List).',
|
||||
'Invalid fileData type. Expected data to be XFile, List<int>, Uint8List, or SnCloudFile.',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -414,7 +414,7 @@ class _MessageItemContent extends StatelessWidget {
|
||||
);
|
||||
case 'text':
|
||||
default:
|
||||
return MarkdownTextContent(content: item.content!);
|
||||
return MarkdownTextContent(content: item.content!, isSelectable: true);
|
||||
}
|
||||
}
|
||||
|
||||
|
212
lib/widgets/content/attachment_preview.dart
Normal file
212
lib/widgets/content/attachment_preview.dart
Normal file
@ -0,0 +1,212 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cross_file/cross_file.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
class AttachmentPreview extends StatelessWidget {
|
||||
final UniversalFile item;
|
||||
final double? progress;
|
||||
final Function(int)? onMove;
|
||||
final Function? onDelete;
|
||||
final Function? onRequestUpload;
|
||||
const AttachmentPreview({
|
||||
super.key,
|
||||
required this.item,
|
||||
this.progress,
|
||||
this.onRequestUpload,
|
||||
this.onMove,
|
||||
this.onDelete,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AspectRatio(
|
||||
aspectRatio:
|
||||
(item.isOnCloud ? (item.data.fileMeta?['ratio'] ?? 1) : 1).toDouble(),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
if (item.isOnCloud) {
|
||||
return CloudFileWidget(item: item.data);
|
||||
} else if (item.data is XFile) {
|
||||
if (item.type == UniversalFileType.image) {
|
||||
return Image.file(File(item.data.path));
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Preview is not supported for ${item.type}',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if (item is List<int> || item is Uint8List) {
|
||||
if (item.type == UniversalFileType.image) {
|
||||
return Image.memory(item.data);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Preview is not supported for ${item.type}',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return Placeholder();
|
||||
},
|
||||
),
|
||||
),
|
||||
if (progress != null)
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (progress != null)
|
||||
Text(
|
||||
'${progress!.toStringAsFixed(2)}%',
|
||||
style: TextStyle(color: Colors.white),
|
||||
)
|
||||
else
|
||||
Text(
|
||||
'uploading'.tr(),
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
Gap(6),
|
||||
Center(child: LinearProgressIndicator(value: progress)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 8,
|
||||
top: 8,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (onDelete != null)
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Icon(
|
||||
Symbols.delete,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
).padding(horizontal: 8, vertical: 6),
|
||||
onTap: () {
|
||||
onDelete?.call();
|
||||
},
|
||||
),
|
||||
if (onDelete != null && onMove != null)
|
||||
SizedBox(
|
||||
height: 26,
|
||||
child: const VerticalDivider(
|
||||
width: 0.3,
|
||||
color: Colors.white,
|
||||
thickness: 0.3,
|
||||
),
|
||||
).padding(horizontal: 2),
|
||||
if (onMove != null)
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Icon(
|
||||
Symbols.keyboard_arrow_up,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
).padding(horizontal: 8, vertical: 6),
|
||||
onTap: () {
|
||||
onMove?.call(-1);
|
||||
},
|
||||
),
|
||||
if (onMove != null)
|
||||
InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: const Icon(
|
||||
Symbols.keyboard_arrow_down,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
).padding(horizontal: 8, vertical: 6),
|
||||
onTap: () {
|
||||
onMove?.call(1);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (onRequestUpload != null)
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
onTap: () => onRequestUpload?.call(),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child:
|
||||
(item.isOnCloud)
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.cloud,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'On-cloud',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.cloud_off,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'On-device',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -8,9 +8,9 @@ import 'package:image_picker/image_picker.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/screens/posts/compose.dart';
|
||||
import 'package:island/services/file.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/content/attachment_preview.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
|
@ -103,6 +103,20 @@ class PostItem extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
MenuAction(
|
||||
title: 'reply'.tr(),
|
||||
image: MenuImage.icon(Symbols.reply),
|
||||
callback: () {
|
||||
context.router.push(PostComposeRoute(repliedPost: item));
|
||||
},
|
||||
),
|
||||
MenuAction(
|
||||
title: 'forward'.tr(),
|
||||
image: MenuImage.icon(Symbols.forward),
|
||||
callback: () {
|
||||
context.router.push(PostComposeRoute(forwardedPost: item));
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
@ -134,6 +148,46 @@ class PostItem extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(item.publisher.nick).bold(),
|
||||
// Add visibility indicator if not public (visibility != 0)
|
||||
if (item.visibility != 0)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
_getVisibilityIcon(item.visibility),
|
||||
size: 14,
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_getVisibilityText(item.visibility).tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(top: 2, bottom: 2),
|
||||
if (item.title?.isNotEmpty ?? false)
|
||||
Text(
|
||||
item.title!,
|
||||
style: Theme.of(context).textTheme.titleMedium
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
if (item.description?.isNotEmpty ?? false)
|
||||
Text(
|
||||
item.description!,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodyMedium?.copyWith(
|
||||
color:
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
).padding(bottom: 8),
|
||||
if (item.content?.isNotEmpty ?? false)
|
||||
MarkdownTextContent(content: item.content!),
|
||||
if ((item.repliedPost != null ||
|
||||
@ -241,6 +295,45 @@ Widget _buildReferencePost(BuildContext context, SnPost item) {
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
// Add visibility indicator for referenced post if not public
|
||||
if (referencePost.visibility != 0)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
_getVisibilityIcon(referencePost.visibility),
|
||||
size: 12,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_getVisibilityText(referencePost.visibility).tr(),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(top: 2, bottom: 2),
|
||||
if (referencePost.title?.isNotEmpty ?? false)
|
||||
Text(
|
||||
referencePost.title!,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 13,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
).padding(top: 2, bottom: 2),
|
||||
if (referencePost.description?.isNotEmpty ?? false)
|
||||
Text(
|
||||
referencePost.description!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
).padding(bottom: 2),
|
||||
if (referencePost.content?.isNotEmpty ?? false)
|
||||
MarkdownTextContent(
|
||||
content: referencePost.content!,
|
||||
@ -490,3 +583,31 @@ class _PostReactionSheet extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to get the appropriate icon for each visibility status
|
||||
IconData _getVisibilityIcon(int visibility) {
|
||||
switch (visibility) {
|
||||
case 1: // Friends
|
||||
return Symbols.group;
|
||||
case 2: // Unlisted
|
||||
return Symbols.link_off;
|
||||
case 3: // Private
|
||||
return Symbols.lock;
|
||||
default: // Public (0) or unknown
|
||||
return Symbols.public;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to get the translation key for each visibility status
|
||||
String _getVisibilityText(int visibility) {
|
||||
switch (visibility) {
|
||||
case 1: // Friends
|
||||
return 'postVisibilityFriends';
|
||||
case 2: // Unlisted
|
||||
return 'postVisibilityUnlisted';
|
||||
case 3: // Private
|
||||
return 'postVisibilityPrivate';
|
||||
default: // Public (0) or unknown
|
||||
return 'postVisibilityPublic';
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ class PostListNotifier extends _$PostListNotifier
|
||||
with CursorPagingNotifierMixin<SnPost> {
|
||||
static const int _pageSize = 20;
|
||||
|
||||
String? pubName;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPost>> build(String? pubName) {
|
||||
this.pubName = pubName;
|
||||
|
@ -6,7 +6,7 @@ part of 'post_list.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$postListNotifierHash() => r'6568b7a5afad71551009d9bc7af26afb4b07c9e5';
|
||||
String _$postListNotifierHash() => r'58a2d5d9a8f742f0a3a3e224a51a811d43903e0d';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
||||
#include <media_kit_video/media_kit_video_plugin.h>
|
||||
#include <pasteboard/pasteboard_plugin.h>
|
||||
#include <record_linux/record_linux_plugin.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <super_native_extensions/super_native_extensions_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
@ -48,6 +49,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
||||
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
||||
g_autoptr(FlPluginRegistrar) record_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin");
|
||||
record_linux_plugin_register_with_registrar(record_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
|
||||
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
|
||||
|
@ -12,6 +12,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
media_kit_libs_linux
|
||||
media_kit_video
|
||||
pasteboard
|
||||
record_linux
|
||||
sqlite3_flutter_libs
|
||||
super_native_extensions
|
||||
url_launcher_linux
|
||||
|
@ -23,6 +23,7 @@ import media_kit_video
|
||||
import package_info_plus
|
||||
import pasteboard
|
||||
import path_provider_foundation
|
||||
import record_macos
|
||||
import shared_preferences_foundation
|
||||
import sqflite_darwin
|
||||
import sqlite3_flutter_libs
|
||||
@ -50,6 +51,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
||||
|
64
pubspec.lock
64
pubspec.lock
@ -1550,6 +1550,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
record:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: record
|
||||
sha256: daeb3f9b3fea9797094433fe6e49a879d8e4ca4207740bc6dc7e4a58764f0817
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
record_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_android
|
||||
sha256: "97d7122455f30de89a01c6c244c839085be6b12abca251fc0e78f67fed73628b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
record_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_ios
|
||||
sha256: "73706ebbece6150654c9d6f57897cf9b622c581148304132ba85dba15df0fdfb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
record_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_linux
|
||||
sha256: "29e7735b05c1944bb6c9b72a36c08d4a1b24117e712d6a9523c003bde12bf484"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
record_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_macos
|
||||
sha256: "02240833fde16c33fcf2c589f3e08d4394b704761b4a3bb609d872ff3043fbbd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
record_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_platform_interface
|
||||
sha256: "8a575828733d4c3cb5983c914696f40db8667eab3538d4c41c50cbb79e722ef4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
record_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_web
|
||||
sha256: f8e536a9c927e52f95326d7540898457eaeefbe0b21a84d3cb3d2d7d4645e8cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.7"
|
||||
record_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_windows
|
||||
sha256: "85a22fc97f6d73ecd67c8ba5f2f472b74ef1d906f795b7970f771a0914167e99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
relative_time:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h>
|
||||
#include <media_kit_video/media_kit_video_plugin_c_api.h>
|
||||
#include <pasteboard/pasteboard_plugin.h>
|
||||
#include <record_windows/record_windows_plugin_c_api.h>
|
||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||
#include <super_native_extensions/super_native_extensions_plugin_c_api.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
@ -51,6 +52,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi"));
|
||||
PasteboardPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
||||
RecordWindowsPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("RecordWindowsPluginCApi"));
|
||||
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
||||
SuperNativeExtensionsPluginCApiRegisterWithRegistrar(
|
||||
|
@ -16,6 +16,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
media_kit_libs_windows_video
|
||||
media_kit_video
|
||||
pasteboard
|
||||
record_windows
|
||||
sqlite3_flutter_libs
|
||||
super_native_extensions
|
||||
url_launcher_windows
|
||||
|
Loading…
x
Reference in New Issue
Block a user