: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.",
|
"accountSettingsHelpContent": "This page allows you to manage your account security, privacy, and other settings. If you need assistance, please contact support.",
|
||||||
"unauthorized": "Unauthorized",
|
"unauthorized": "Unauthorized",
|
||||||
"unauthorizedHint": "You're not signed in or session expired, please sign in again.",
|
"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": "隐藏底部导航",
|
"settingsHideBottomNav": "隐藏底部导航",
|
||||||
"settingsSoundEffects": "音效",
|
"settingsSoundEffects": "音效",
|
||||||
"settingsAprilFoolFeatures": "愚人节功能",
|
"settingsAprilFoolFeatures": "愚人节功能",
|
||||||
"settingsEnterToSend": "按下 Enter 发送"
|
"settingsEnterToSend": "按下 Enter 发送",
|
||||||
|
"postVisibility": "可见性",
|
||||||
|
"postVisibilityPublic": "公开",
|
||||||
|
"postVisibilityFriends": "仅好友可见",
|
||||||
|
"postVisibilityUnlisted": "不公开",
|
||||||
|
"postVisibilityPrivate": "私密"
|
||||||
}
|
}
|
@ -286,5 +286,10 @@
|
|||||||
"settingsHideBottomNav": "隱藏底部導航",
|
"settingsHideBottomNav": "隱藏底部導航",
|
||||||
"settingsSoundEffects": "音效",
|
"settingsSoundEffects": "音效",
|
||||||
"settingsAprilFoolFeatures": "愚人節功能",
|
"settingsAprilFoolFeatures": "愚人節功能",
|
||||||
"settingsEnterToSend": "按下 Enter 傳送"
|
"settingsEnterToSend": "按下 Enter 傳送",
|
||||||
|
"postVisibility": "可見性",
|
||||||
|
"postVisibilityPublic": "公開",
|
||||||
|
"postVisibilityFriends": "僅好友可見",
|
||||||
|
"postVisibilityUnlisted": "不公開",
|
||||||
|
"postVisibilityPrivate": "私密"
|
||||||
}
|
}
|
@ -1071,10 +1071,17 @@ class PostComposeRoute extends _i27.PageRouteInfo<PostComposeRouteArgs> {
|
|||||||
PostComposeRoute({
|
PostComposeRoute({
|
||||||
_i28.Key? key,
|
_i28.Key? key,
|
||||||
_i30.SnPost? originalPost,
|
_i30.SnPost? originalPost,
|
||||||
|
_i30.SnPost? repliedPost,
|
||||||
|
_i30.SnPost? forwardedPost,
|
||||||
List<_i27.PageRouteInfo>? children,
|
List<_i27.PageRouteInfo>? children,
|
||||||
}) : super(
|
}) : super(
|
||||||
PostComposeRoute.name,
|
PostComposeRoute.name,
|
||||||
args: PostComposeRouteArgs(key: key, originalPost: originalPost),
|
args: PostComposeRouteArgs(
|
||||||
|
key: key,
|
||||||
|
originalPost: originalPost,
|
||||||
|
repliedPost: repliedPost,
|
||||||
|
forwardedPost: forwardedPost,
|
||||||
|
),
|
||||||
initialChildren: children,
|
initialChildren: children,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1089,32 +1096,50 @@ class PostComposeRoute extends _i27.PageRouteInfo<PostComposeRouteArgs> {
|
|||||||
return _i18.PostComposeScreen(
|
return _i18.PostComposeScreen(
|
||||||
key: args.key,
|
key: args.key,
|
||||||
originalPost: args.originalPost,
|
originalPost: args.originalPost,
|
||||||
|
repliedPost: args.repliedPost,
|
||||||
|
forwardedPost: args.forwardedPost,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PostComposeRouteArgs {
|
class PostComposeRouteArgs {
|
||||||
const PostComposeRouteArgs({this.key, this.originalPost});
|
const PostComposeRouteArgs({
|
||||||
|
this.key,
|
||||||
|
this.originalPost,
|
||||||
|
this.repliedPost,
|
||||||
|
this.forwardedPost,
|
||||||
|
});
|
||||||
|
|
||||||
final _i28.Key? key;
|
final _i28.Key? key;
|
||||||
|
|
||||||
final _i30.SnPost? originalPost;
|
final _i30.SnPost? originalPost;
|
||||||
|
|
||||||
|
final _i30.SnPost? repliedPost;
|
||||||
|
|
||||||
|
final _i30.SnPost? forwardedPost;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'PostComposeRouteArgs{key: $key, originalPost: $originalPost}';
|
return 'PostComposeRouteArgs{key: $key, originalPost: $originalPost, repliedPost: $repliedPost, forwardedPost: $forwardedPost}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
if (identical(this, other)) return true;
|
if (identical(this, other)) return true;
|
||||||
if (other is! PostComposeRouteArgs) return false;
|
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
|
@override
|
||||||
int get hashCode => key.hashCode ^ originalPost.hashCode;
|
int get hashCode =>
|
||||||
|
key.hashCode ^
|
||||||
|
originalPost.hashCode ^
|
||||||
|
repliedPost.hashCode ^
|
||||||
|
forwardedPost.hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
|
@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/pods/userinfo.dart';
|
||||||
@ -63,7 +64,10 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
|||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putMediaToCloud(
|
||||||
fileData: result,
|
fileData: UniversalFile(
|
||||||
|
data: result,
|
||||||
|
type: UniversalFileType.image,
|
||||||
|
),
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
filename: result.name,
|
filename: result.name,
|
||||||
|
@ -527,7 +527,10 @@ class EditChatScreen extends HookConsumerWidget {
|
|||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putMediaToCloud(
|
||||||
fileData: result,
|
fileData: UniversalFile(
|
||||||
|
data: result,
|
||||||
|
type: UniversalFileType.image,
|
||||||
|
),
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
filename: result.name,
|
filename: result.name,
|
||||||
|
@ -17,12 +17,12 @@ import 'package:island/pods/database.dart';
|
|||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/websocket.dart';
|
import 'package:island/pods/websocket.dart';
|
||||||
import 'package:island/route.gr.dart';
|
import 'package:island/route.gr.dart';
|
||||||
import 'package:island/screens/posts/compose.dart';
|
|
||||||
import 'package:island/services/responsive.dart';
|
import 'package:island/services/responsive.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/chat/call_overlay.dart';
|
import 'package:island/widgets/chat/call_overlay.dart';
|
||||||
import 'package:island/widgets/chat/message_item.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/content/cloud_files.dart';
|
||||||
import 'package:island/widgets/response.dart';
|
import 'package:island/widgets/response.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
@ -514,7 +514,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
loading: () => const Text('Loading...'),
|
loading: () => const Text('Loading...'),
|
||||||
error:
|
error:
|
||||||
(err, __) => ResponseErrorWidget(
|
(err, _) => ResponseErrorWidget(
|
||||||
error: err,
|
error: err,
|
||||||
onRetry: () => messagesNotifier.loadInitial(),
|
onRetry: () => messagesNotifier.loadInitial(),
|
||||||
),
|
),
|
||||||
@ -615,7 +615,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
progress: null,
|
progress: null,
|
||||||
showAvatar: false,
|
showAvatar: false,
|
||||||
),
|
),
|
||||||
error: (_, __) => const SizedBox.shrink(),
|
error: (_, _) => const SizedBox.shrink(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -680,7 +680,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
attachments.value = newAttachments;
|
attachments.value = newAttachments;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
error: (_, __) => const SizedBox.shrink(),
|
error: (_, _) => const SizedBox.shrink(),
|
||||||
loading: () => const SizedBox.shrink(),
|
loading: () => const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -788,7 +788,7 @@ class _ChatInput extends ConsumerWidget {
|
|||||||
onMove: (delta) => onMoveAttachment(idx, delta),
|
onMove: (delta) => onMoveAttachment(idx, delta),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
separatorBuilder: (_, __) => const Gap(8),
|
separatorBuilder: (_, _) => const Gap(8),
|
||||||
),
|
),
|
||||||
).padding(top: 12),
|
).padding(top: 12),
|
||||||
if (messageReplyingTo != null ||
|
if (messageReplyingTo != null ||
|
||||||
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
import 'package:island/models/realm.dart';
|
import 'package:island/models/realm.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
@ -99,7 +100,10 @@ class EditPublisherScreen extends HookConsumerWidget {
|
|||||||
if (token == null) throw ArgumentError('Token is null');
|
if (token == null) throw ArgumentError('Token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putMediaToCloud(
|
||||||
fileData: result,
|
fileData: UniversalFile(
|
||||||
|
data: result,
|
||||||
|
type: UniversalFileType.image,
|
||||||
|
),
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
filename: result.name,
|
filename: result.name,
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:dio/dio.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/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.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:island/widgets/post/publishers_modal.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:pasteboard/pasteboard.dart';
|
import 'package:pasteboard/pasteboard.dart';
|
||||||
@ -53,7 +52,14 @@ class PostEditScreen extends HookConsumerWidget {
|
|||||||
@RoutePage()
|
@RoutePage()
|
||||||
class PostComposeScreen extends HookConsumerWidget {
|
class PostComposeScreen extends HookConsumerWidget {
|
||||||
final SnPost? originalPost;
|
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
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@ -90,9 +96,14 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
text: originalPost?.description,
|
text: originalPost?.description,
|
||||||
);
|
);
|
||||||
final contentController = useTextEditingController(
|
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);
|
final submitting = useState(false);
|
||||||
|
|
||||||
Future<void> pickPhotoMedia() async {
|
Future<void> pickPhotoMedia() async {
|
||||||
@ -188,12 +199,18 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
await client.request(
|
await client.request(
|
||||||
originalPost == null ? '/posts' : '/posts/${originalPost!.id}',
|
originalPost == null ? '/posts' : '/posts/${originalPost!.id}',
|
||||||
data: {
|
data: {
|
||||||
|
'title': titleController.text,
|
||||||
|
'description': descriptionController.text,
|
||||||
'content': contentController.text,
|
'content': contentController.text,
|
||||||
|
'visibility':
|
||||||
|
visibility.value, // Add visibility field to API request
|
||||||
'attachments':
|
'attachments':
|
||||||
attachments.value
|
attachments.value
|
||||||
.where((e) => e.isOnCloud)
|
.where((e) => e.isOnCloud)
|
||||||
.map((e) => e.data.id)
|
.map((e) => e.data.id)
|
||||||
.toList(),
|
.toList(),
|
||||||
|
if (repliedPost != null) 'replied_post_id': repliedPost!.id,
|
||||||
|
if (forwardedPost != null) 'forwarded_post_id': forwardedPost!.id,
|
||||||
},
|
},
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: {'X-Pub': currentPublisher.value?.name},
|
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;
|
final clipboard = await Pasteboard.image;
|
||||||
if (clipboard == null) return;
|
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;
|
if (event is! RawKeyDownEvent) return;
|
||||||
|
|
||||||
final isPaste = event.logicalKey == LogicalKeyboardKey.keyV;
|
final isPaste = event.logicalKey == LogicalKeyboardKey.keyV;
|
||||||
final isModifierPressed = event.isMetaPressed || event.isControlPressed;
|
final isModifierPressed = event.isMetaPressed || event.isControlPressed;
|
||||||
|
|
||||||
if (isPaste && isModifierPressed) {
|
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(
|
body: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
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(
|
Expanded(
|
||||||
child: Row(
|
child: Row(
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
@ -324,7 +462,52 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
padding: EdgeInsets.symmetric(vertical: 16),
|
padding: EdgeInsets.symmetric(vertical: 16),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
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(
|
TextField(
|
||||||
controller: titleController,
|
controller: titleController,
|
||||||
decoration: InputDecoration.collapsed(
|
decoration: InputDecoration.collapsed(
|
||||||
@ -348,7 +531,7 @@ class PostComposeScreen extends HookConsumerWidget {
|
|||||||
const Gap(8),
|
const Gap(8),
|
||||||
RawKeyboardListener(
|
RawKeyboardListener(
|
||||||
focusNode: FocusNode(),
|
focusNode: FocusNode(),
|
||||||
onKey: _handleKeyPress,
|
onKey: handleKeyPress,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: contentController,
|
controller: contentController,
|
||||||
style: TextStyle(fontSize: 14),
|
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:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -215,7 +215,10 @@ class EditRealmScreen extends HookConsumerWidget {
|
|||||||
if (token == null) throw ArgumentError('Access token is null');
|
if (token == null) throw ArgumentError('Access token is null');
|
||||||
final cloudFile =
|
final cloudFile =
|
||||||
await putMediaToCloud(
|
await putMediaToCloud(
|
||||||
fileData: result,
|
fileData: UniversalFile(
|
||||||
|
data: result,
|
||||||
|
type: UniversalFileType.image,
|
||||||
|
),
|
||||||
atk: token,
|
atk: token,
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
filename: result.name,
|
filename: result.name,
|
||||||
|
@ -39,7 +39,7 @@ Future<XFile?> cropImage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Completer<SnCloudFile?> putMediaToCloud({
|
Completer<SnCloudFile?> putMediaToCloud({
|
||||||
required dynamic fileData, // Can be XFile or List<int> (Uint8List)
|
required UniversalFile fileData,
|
||||||
required String atk,
|
required String atk,
|
||||||
required String baseUrl,
|
required String baseUrl,
|
||||||
String? filename,
|
String? filename,
|
||||||
@ -51,21 +51,27 @@ Completer<SnCloudFile?> putMediaToCloud({
|
|||||||
String actualMimetype = mimetype ?? '';
|
String actualMimetype = mimetype ?? '';
|
||||||
Uint8List? byteData;
|
Uint8List? byteData;
|
||||||
|
|
||||||
if (fileData is XFile) {
|
// Handle the data based on what's in the UniversalFile
|
||||||
file = fileData;
|
final data = fileData.data;
|
||||||
actualFilename = filename ?? fileData.name;
|
|
||||||
actualMimetype = mimetype ?? fileData.mimeType ?? '';
|
if (data is XFile) {
|
||||||
} else if (fileData is List<int> || fileData is Uint8List) {
|
file = data;
|
||||||
byteData = fileData is List<int> ? Uint8List.fromList(fileData) : fileData;
|
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';
|
actualFilename = filename ?? 'uploaded_file';
|
||||||
actualMimetype = mimetype ?? 'application/octet-stream';
|
actualMimetype = mimetype ?? 'application/octet-stream';
|
||||||
if (mimetype == null) {
|
if (mimetype == null) {
|
||||||
throw ArgumentError('Mimetype is required when providing raw bytes.');
|
throw ArgumentError('Mimetype is required when providing raw bytes.');
|
||||||
}
|
}
|
||||||
file = XFile.fromData(byteData!, mimeType: actualMimetype);
|
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 {
|
} else {
|
||||||
throw ArgumentError(
|
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':
|
case 'text':
|
||||||
default:
|
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/models/file.dart';
|
||||||
import 'package:island/pods/config.dart';
|
import 'package:island/pods/config.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/screens/posts/compose.dart';
|
|
||||||
import 'package:island/services/file.dart';
|
import 'package:island/services/file.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
|
import 'package:island/widgets/content/attachment_preview.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.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,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(item.publisher.nick).bold(),
|
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)
|
if (item.content?.isNotEmpty ?? false)
|
||||||
MarkdownTextContent(content: item.content!),
|
MarkdownTextContent(content: item.content!),
|
||||||
if ((item.repliedPost != null ||
|
if ((item.repliedPost != null ||
|
||||||
@ -241,6 +295,45 @@ Widget _buildReferencePost(BuildContext context, SnPost item) {
|
|||||||
fontSize: 14,
|
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)
|
if (referencePost.content?.isNotEmpty ?? false)
|
||||||
MarkdownTextContent(
|
MarkdownTextContent(
|
||||||
content: referencePost.content!,
|
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> {
|
with CursorPagingNotifierMixin<SnPost> {
|
||||||
static const int _pageSize = 20;
|
static const int _pageSize = 20;
|
||||||
|
|
||||||
String? pubName;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnPost>> build(String? pubName) {
|
Future<CursorPagingData<SnPost>> build(String? pubName) {
|
||||||
this.pubName = pubName;
|
this.pubName = pubName;
|
||||||
|
@ -6,7 +6,7 @@ part of 'post_list.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$postListNotifierHash() => r'6568b7a5afad71551009d9bc7af26afb4b07c9e5';
|
String _$postListNotifierHash() => r'58a2d5d9a8f742f0a3a3e224a51a811d43903e0d';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
|
||||||
#include <media_kit_video/media_kit_video_plugin.h>
|
#include <media_kit_video/media_kit_video_plugin.h>
|
||||||
#include <pasteboard/pasteboard_plugin.h>
|
#include <pasteboard/pasteboard_plugin.h>
|
||||||
|
#include <record_linux/record_linux_plugin.h>
|
||||||
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||||
#include <super_native_extensions/super_native_extensions_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>
|
||||||
@ -48,6 +49,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
|||||||
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
||||||
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
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 =
|
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
|
||||||
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
|
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_libs_linux
|
||||||
media_kit_video
|
media_kit_video
|
||||||
pasteboard
|
pasteboard
|
||||||
|
record_linux
|
||||||
sqlite3_flutter_libs
|
sqlite3_flutter_libs
|
||||||
super_native_extensions
|
super_native_extensions
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
|
@ -23,6 +23,7 @@ import media_kit_video
|
|||||||
import package_info_plus
|
import package_info_plus
|
||||||
import pasteboard
|
import pasteboard
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
import record_macos
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import sqflite_darwin
|
import sqflite_darwin
|
||||||
import sqlite3_flutter_libs
|
import sqlite3_flutter_libs
|
||||||
@ -50,6 +51,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
|
||||||
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"))
|
||||||
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
|
||||||
|
64
pubspec.lock
64
pubspec.lock
@ -1550,6 +1550,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
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:
|
relative_time:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h>
|
#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 <media_kit_video/media_kit_video_plugin_c_api.h>
|
||||||
#include <pasteboard/pasteboard_plugin.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 <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
|
||||||
#include <super_native_extensions/super_native_extensions_plugin_c_api.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>
|
||||||
@ -51,6 +52,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||||||
registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi"));
|
registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi"));
|
||||||
PasteboardPluginRegisterWithRegistrar(
|
PasteboardPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
||||||
|
RecordWindowsPluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("RecordWindowsPluginCApi"));
|
||||||
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
Sqlite3FlutterLibsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
|
||||||
SuperNativeExtensionsPluginCApiRegisterWithRegistrar(
|
SuperNativeExtensionsPluginCApiRegisterWithRegistrar(
|
||||||
|
@ -16,6 +16,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||||||
media_kit_libs_windows_video
|
media_kit_libs_windows_video
|
||||||
media_kit_video
|
media_kit_video
|
||||||
pasteboard
|
pasteboard
|
||||||
|
record_windows
|
||||||
sqlite3_flutter_libs
|
sqlite3_flutter_libs
|
||||||
super_native_extensions
|
super_native_extensions
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
|
Loading…
x
Reference in New Issue
Block a user