diff --git a/.github/workflows/flutter_ci.yaml b/.github/workflows/flutter_ci.yaml
index b944187ec4..3e64bcd83f 100644
--- a/.github/workflows/flutter_ci.yaml
+++ b/.github/workflows/flutter_ci.yaml
@@ -172,7 +172,7 @@ jobs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
- sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
+ sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev libmpv-dev mpv
fi
shell: bash
@@ -272,7 +272,7 @@ jobs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
- sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
+ sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev libmpv-dev mpv
shell: bash
- name: Enable Flutter Desktop
@@ -319,6 +319,12 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
+ - name: Install video dependency
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install libmpv-dev mpv
+ shell: bash
+
- name: Flutter Integration Test 1
uses: ./.github/actions/flutter_integration_test
with:
@@ -343,6 +349,12 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
+ - name: Install video dependency
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install libmpv-dev mpv
+ shell: bash
+
- name: Flutter Integration Test 2
uses: ./.github/actions/flutter_integration_test
with:
@@ -367,6 +379,12 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
+ - name: Install video dependency
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install libmpv-dev mpv
+ shell: bash
+
- name: Flutter Integration Test 3
uses: ./.github/actions/flutter_integration_test
with:
diff --git a/frontend/appflowy_flutter/android/app/src/main/AndroidManifest.xml b/frontend/appflowy_flutter/android/app/src/main/AndroidManifest.xml
index 351994354d..279b17320c 100644
--- a/frontend/appflowy_flutter/android/app/src/main/AndroidManifest.xml
+++ b/frontend/appflowy_flutter/android/app/src/main/AndroidManifest.xml
@@ -58,4 +58,11 @@
+
+
+
\ No newline at end of file
diff --git a/frontend/appflowy_flutter/ios/Podfile.lock b/frontend/appflowy_flutter/ios/Podfile.lock
index 93a8eb77e1..5a2d069c36 100644
--- a/frontend/appflowy_flutter/ios/Podfile.lock
+++ b/frontend/appflowy_flutter/ios/Podfile.lock
@@ -58,6 +58,12 @@ PODS:
- Flutter
- keyboard_height_plugin (0.0.1):
- Flutter
+ - media_kit_libs_ios_video (1.0.4):
+ - Flutter
+ - media_kit_native_event_loop (1.0.0):
+ - Flutter
+ - media_kit_video (0.0.1):
+ - Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
@@ -66,6 +72,8 @@ PODS:
- permission_handler_apple (9.3.0):
- Flutter
- ReachabilitySwift (5.0.0)
+ - screen_brightness_ios (0.1.0):
+ - Flutter
- SDWebImage (5.14.2):
- SDWebImage/Core (= 5.14.2)
- SDWebImage/Core (5.14.2)
@@ -83,6 +91,10 @@ PODS:
- Toast (4.0.0)
- url_launcher_ios (0.0.1):
- Flutter
+ - volume_controller (0.0.1):
+ - Flutter
+ - wakelock_plus (0.0.1):
+ - Flutter
DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
@@ -98,14 +110,20 @@ DEPENDENCIES:
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
- keyboard_height_plugin (from `.symlinks/plugins/keyboard_height_plugin/ios`)
+ - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
+ - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
+ - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
+ - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
+ - volume_controller (from `.symlinks/plugins/volume_controller/ios`)
+ - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
SPEC REPOS:
trunk:
@@ -143,12 +161,20 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/irondash_engine_context/ios"
keyboard_height_plugin:
:path: ".symlinks/plugins/keyboard_height_plugin/ios"
+ media_kit_libs_ios_video:
+ :path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
+ media_kit_native_event_loop:
+ :path: ".symlinks/plugins/media_kit_native_event_loop/ios"
+ media_kit_video:
+ :path: ".symlinks/plugins/media_kit_video/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
+ screen_brightness_ios:
+ :path: ".symlinks/plugins/screen_brightness_ios/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
@@ -159,6 +185,10 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/super_native_extensions/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
+ volume_controller:
+ :path: ".symlinks/plugins/volume_controller/ios"
+ wakelock_plus:
+ :path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
@@ -176,10 +206,14 @@ SPEC CHECKSUMS:
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86
+ media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
+ media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
+ media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
+ screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
@@ -188,6 +222,8 @@ SPEC CHECKSUMS:
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
+ volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
+ wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
PODFILE CHECKSUM: d0d9b4ff572d8695c38eb3f9b490f55cdfc57eca
diff --git a/frontend/appflowy_flutter/ios/Runner/Info.plist b/frontend/appflowy_flutter/ios/Runner/Info.plist
index 8c605b9d3a..5ec528b05e 100644
--- a/frontend/appflowy_flutter/ios/Runner/Info.plist
+++ b/frontend/appflowy_flutter/ios/Runner/Info.plist
@@ -66,5 +66,10 @@
UIViewControllerBasedStatusBarAppearance
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
\ No newline at end of file
diff --git a/frontend/appflowy_flutter/lib/main.dart b/frontend/appflowy_flutter/lib/main.dart
index 9f140489c4..bee524b574 100644
--- a/frontend/appflowy_flutter/lib/main.dart
+++ b/frontend/appflowy_flutter/lib/main.dart
@@ -1,9 +1,12 @@
import 'package:scaled_app/scaled_app.dart';
+import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
+
import 'startup/startup.dart';
Future main() async {
ScaledWidgetsFlutterBinding.ensureInitialized(scaleFactor: (_) => 1.0);
+ VideoBlockKit.ensureInitialized();
await runAppFlowy();
}
diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_configuration.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_configuration.dart
index 39cd608d0e..5f2d6e5c70 100644
--- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_configuration.dart
+++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_configuration.dart
@@ -5,6 +5,8 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/mo
import 'package:appflowy/plugins/document/presentation/editor_plugins/code_block/code_block_copy_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/video/video_menu.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/video/video_placeholder.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
@@ -110,7 +112,7 @@ Map getEditorBuilderMap({
showMenu: true,
menuBuilder: (Node node, CustomImageBlockComponentState state) =>
Positioned(
- top: 0,
+ top: 10,
right: 10,
child: ImageMenu(node: node, state: state),
),
@@ -180,7 +182,6 @@ Map getEditorBuilderMap({
configuration: configuration,
),
CodeBlockKeys.type: CodeBlockComponentBuilder(
- editorState: editorState,
configuration: configuration.copyWith(
textStyle: (_) => styleCustomizer.codeBlockStyleBuilder(),
placeholderTextStyle: (_) => styleCustomizer.codeBlockStyleBuilder(),
@@ -228,6 +229,16 @@ Map getEditorBuilderMap({
errorBlockComponentBuilderKey: ErrorBlockComponentBuilder(
configuration: configuration,
),
+ VideoBlockKeys.type: VideoBlockComponentBuilder(
+ configuration: configuration,
+ showMenu: true,
+ menuBuilder: (node, state) => Positioned(
+ top: 10,
+ right: 10,
+ child: VideoMenu(node: node, state: state),
+ ),
+ placeholderBuilder: (node) => VideoPlaceholder(node: node),
+ ),
};
final builders = {
diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart
index 13d2ba6ab9..996aa4ced1 100644
--- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart
+++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart
@@ -388,6 +388,7 @@ class _AppFlowyEditorPageState extends State {
emojiMenuItem,
autoGeneratorMenuItem,
dateMenuItem,
+ videoBlockItem(LocaleKeys.document_plugins_video_label.tr()),
];
}
diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart
index c389977333..722a79c2f5 100644
--- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart
+++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart
@@ -1,5 +1,7 @@
import 'dart:io';
+import 'package:flutter/material.dart';
+
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
@@ -13,7 +15,6 @@ import 'package:appflowy/util/string_extension.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide ResizableImage;
import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:string_validator/string_validator.dart';
@@ -109,10 +110,7 @@ class CustomImageBlockComponentBuilder extends BlockComponentBuilder {
node: node,
showActions: showActions(node),
configuration: configuration,
- actionBuilder: (context, state) => actionBuilder(
- blockComponentContext,
- state,
- ),
+ actionBuilder: (_, state) => actionBuilder(blockComponentContext, state),
showMenu: showMenu,
menuBuilder: menuBuilder,
);
diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/add_block_toolbar_item.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/add_block_toolbar_item.dart
index d0be5af466..7ce86c3035 100644
--- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/add_block_toolbar_item.dart
+++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/add_block_toolbar_item.dart
@@ -197,6 +197,15 @@ class _AddBlockMenu extends StatelessWidget {
},
),
+ // video
+ TypeOptionMenuItemValue(
+ value: VideoBlockKeys.type,
+ backgroundColor: colorMap[VideoBlockKeys.type]!,
+ text: LocaleKeys.document_plugins_video_label.tr(),
+ icon: FlowySvgs.m_add_block_video_s,
+ onTap: (_, __) => _insertBlock(videoBlockNode()),
+ ),
+
// date
TypeOptionMenuItemValue(
value: ParagraphBlockKeys.type,
@@ -287,6 +296,7 @@ class _AddBlockMenu extends StatelessWidget {
NumberedListBlockKeys.type: const Color(0xFFA35F94),
ToggleListBlockKeys.type: const Color(0xFFA35F94),
ImageBlockKeys.type: const Color(0xFFBAAC74),
+ VideoBlockKeys.type: const Color(0xFFBAAC74),
MentionBlockKeys.type: const Color(0xFF40AAB8),
DividerBlockKeys.type: const Color(0xFF4BB299),
CalloutBlockKeys.type: const Color(0xFF66599B),
@@ -303,6 +313,7 @@ class _AddBlockMenu extends StatelessWidget {
NumberedListBlockKeys.type: const Color(0xFFFFB9EF),
ToggleListBlockKeys.type: const Color(0xFFFFB9EF),
ImageBlockKeys.type: const Color(0xFFFDEDA7),
+ VideoBlockKeys.type: const Color(0xFFFDEDA7),
MentionBlockKeys.type: const Color(0xFF91EAF5),
DividerBlockKeys.type: const Color(0xFF98F4CD),
CalloutBlockKeys.type: const Color(0xFFCABDFF),
diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/upload_video_menu.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/upload_video_menu.dart
new file mode 100644
index 0000000000..2b2752e3f5
--- /dev/null
+++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/upload_video_menu.dart
@@ -0,0 +1,93 @@
+import 'package:flutter/material.dart';
+
+import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:appflowy/shared/patterns/common_patterns.dart';
+import 'package:appflowy_editor/appflowy_editor.dart' hide ColorOption;
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
+
+class UploadVideoMenu extends StatefulWidget {
+ const UploadVideoMenu({
+ super.key,
+ required this.onUrlSubmitted,
+ this.onSelectedColor,
+ });
+
+ final void Function(String url) onUrlSubmitted;
+ final void Function(String color)? onSelectedColor;
+
+ @override
+ State createState() => _UploadVideoMenuState();
+}
+
+class _UploadVideoMenuState extends State {
+ @override
+ Widget build(BuildContext context) {
+ final constraints =
+ PlatformExtension.isMobile ? const BoxConstraints(minHeight: 92) : null;
+
+ return Container(
+ padding: const EdgeInsets.all(8.0),
+ constraints: constraints,
+ child: _EmbedUrl(onSubmit: widget.onUrlSubmitted),
+ );
+ }
+}
+
+class _EmbedUrl extends StatefulWidget {
+ const _EmbedUrl({required this.onSubmit});
+
+ final void Function(String url) onSubmit;
+
+ @override
+ State<_EmbedUrl> createState() => _EmbedUrlState();
+}
+
+class _EmbedUrlState extends State<_EmbedUrl> {
+ bool isUrlValid = true;
+ String inputText = '';
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ FlowyTextField(
+ hintText: LocaleKeys.document_plugins_video_placeholder.tr(),
+ onChanged: (value) => inputText = value,
+ onEditingComplete: submit,
+ ),
+ if (!isUrlValid) ...[
+ const VSpace(8),
+ FlowyText(
+ LocaleKeys.document_plugins_video_invalidVideoUrl.tr(),
+ color: Theme.of(context).colorScheme.error,
+ ),
+ ],
+ const VSpace(8),
+ SizedBox(
+ width: 160,
+ child: FlowyButton(
+ showDefaultBoxDecorationOnMobile: true,
+ margin: const EdgeInsets.all(8.0),
+ text: FlowyText(
+ LocaleKeys.document_plugins_video_insertVideo.tr(),
+ textAlign: TextAlign.center,
+ ),
+ onTap: submit,
+ ),
+ ),
+ ],
+ );
+ }
+
+ void submit() {
+ if (checkUrlValidity(inputText)) {
+ return widget.onSubmit(inputText);
+ }
+
+ setState(() => isUrlValid = false);
+ }
+
+ bool checkUrlValidity(String url) => videoUrlRegex.hasMatch(url);
+}
diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/video_menu.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/video_menu.dart
new file mode 100644
index 0000000000..a82156586e
--- /dev/null
+++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/video_menu.dart
@@ -0,0 +1,314 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+import 'package:appflowy/generated/flowy_svgs.g.dart';
+import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_block_action_widget.dart';
+import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart';
+import 'package:appflowy/mobile/presentation/widgets/flowy_option_tile.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/align_toolbar_item/align_toolbar_item.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/block_menu/block_menu_button.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
+import 'package:appflowy/startup/startup.dart';
+import 'package:appflowy/workspace/presentation/home/toast.dart';
+import 'package:appflowy_editor/appflowy_editor.dart';
+import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
+import 'package:appflowy_popover/appflowy_popover.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
+import 'package:flowy_infra_ui/widget/ignore_parent_gesture.dart';
+import 'package:go_router/go_router.dart';
+import 'package:provider/provider.dart';
+
+class VideoMenu extends StatefulWidget {
+ const VideoMenu({
+ super.key,
+ required this.node,
+ required this.state,
+ });
+
+ final Node node;
+ final VideoBlockComponentState state;
+
+ @override
+ State createState() => _VideoMenuState();
+}
+
+class _VideoMenuState extends State {
+ late final String? url = widget.node.attributes[VideoBlockKeys.url];
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+ return Container(
+ height: 32,
+ decoration: BoxDecoration(
+ color: theme.cardColor,
+ borderRadius: BorderRadius.circular(4.0),
+ boxShadow: [
+ BoxShadow(
+ blurRadius: 5,
+ spreadRadius: 1,
+ color: Colors.black.withOpacity(0.1),
+ ),
+ ],
+ ),
+ child: PlatformExtension.isMobile
+ ? MenuBlockButton(
+ tooltip: LocaleKeys.button_edit.tr(),
+ iconData: FlowySvgs.more_s,
+ onTap: showMobileMenu,
+ )
+ : Row(
+ children: [
+ const HSpace(4),
+ MenuBlockButton(
+ tooltip: LocaleKeys.editor_copyLink.tr(),
+ iconData: FlowySvgs.copy_s,
+ onTap: copyVideoLink,
+ ),
+ const HSpace(4),
+ _VideoAlignButton(
+ node: widget.node,
+ state: widget.state,
+ ),
+ const _Divider(),
+ MenuBlockButton(
+ tooltip: LocaleKeys.button_delete.tr(),
+ iconData: FlowySvgs.delete_s,
+ onTap: deleteVideo,
+ ),
+ const HSpace(4),
+ ],
+ ),
+ );
+ }
+
+ void copyVideoLink() {
+ if (url != null) {
+ Clipboard.setData(ClipboardData(text: url!));
+ showSnackBarMessage(
+ context,
+ LocaleKeys.document_plugins_video_copiedToPasteBoard.tr(),
+ );
+ }
+ }
+
+ void showMobileMenu() {
+ final editorState = context.read()
+ ..updateSelectionWithReason(null, extraInfo: {});
+ final src = widget.node.attributes[VideoBlockKeys.url];
+ showMobileBottomSheet(
+ context,
+ showHeader: true,
+ showCloseButton: true,
+ showDragHandle: true,
+ title: LocaleKeys.document_plugins_action.tr(),
+ builder: (context) {
+ return BlockActionBottomSheet(
+ extendActionWidgets: [
+ FlowyOptionTile.text(
+ showTopBorder: false,
+ text: LocaleKeys.editor_copyLink.tr(),
+ leftIcon: const FlowySvg(
+ FlowySvgs.m_field_copy_s,
+ ),
+ onTap: () async {
+ context.pop();
+ showSnackBarMessage(
+ context,
+ LocaleKeys.document_plugins_video_copiedToPasteBoard.tr(),
+ );
+ await getIt().setPlainText(src);
+ },
+ ),
+ ],
+ onAction: (action) async {
+ context.pop();
+
+ final transaction = editorState.transaction;
+ switch (action) {
+ case BlockActionBottomSheetType.delete:
+ transaction.deleteNode(widget.node);
+ break;
+ case BlockActionBottomSheetType.duplicate:
+ transaction.insertNode(
+ widget.node.path.next,
+ widget.node.copyWith(),
+ );
+ break;
+ case BlockActionBottomSheetType.insertAbove:
+ case BlockActionBottomSheetType.insertBelow:
+ final path = action == BlockActionBottomSheetType.insertAbove
+ ? widget.node.path
+ : widget.node.path.next;
+ transaction
+ ..insertNode(path, paragraphNode())
+ ..afterSelection = Selection.collapsed(Position(path: path));
+ break;
+ default:
+ }
+
+ if (transaction.operations.isNotEmpty) {
+ await editorState.apply(transaction);
+ }
+ },
+ );
+ },
+ );
+ }
+
+ Future deleteVideo() async {
+ final node = widget.node;
+ final editorState = context.read();
+ final transaction = editorState.transaction;
+ transaction.deleteNode(node);
+ transaction.afterSelection = null;
+ await editorState.apply(transaction);
+ }
+}
+
+class _VideoAlignButton extends StatefulWidget {
+ const _VideoAlignButton({
+ required this.node,
+ required this.state,
+ });
+
+ final Node node;
+ final VideoBlockComponentState state;
+
+ @override
+ State<_VideoAlignButton> createState() => _VideoAlignButtonState();
+}
+
+const interceptorKey = 'video-align';
+
+class _VideoAlignButtonState extends State<_VideoAlignButton> {
+ final gestureInterceptor = SelectionGestureInterceptor(
+ key: interceptorKey,
+ canTap: (_) => false,
+ );
+
+ String get align =>
+ widget.node.attributes[VideoBlockKeys.alignment] ?? centerAlignmentKey;
+ final popoverController = PopoverController();
+ late final EditorState editorState;
+
+ @override
+ void initState() {
+ super.initState();
+ editorState = context.read();
+ }
+
+ @override
+ void dispose() {
+ allowMenuClose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return IgnoreParentGestureWidget(
+ child: AppFlowyPopover(
+ onClose: allowMenuClose,
+ controller: popoverController,
+ windowPadding: const EdgeInsets.all(0),
+ margin: const EdgeInsets.all(0),
+ direction: PopoverDirection.bottomWithCenterAligned,
+ offset: const Offset(0, 10),
+ child: MenuBlockButton(
+ tooltip: LocaleKeys.document_plugins_optionAction_align.tr(),
+ iconData: iconFor(align),
+ ),
+ popupBuilder: (_) {
+ preventMenuClose();
+ return _AlignButtons(onAlignChanged: onAlignChanged);
+ },
+ ),
+ );
+ }
+
+ void onAlignChanged(String align) {
+ popoverController.close();
+
+ final transaction = editorState.transaction;
+ transaction.updateNode(widget.node, {VideoBlockKeys.alignment: align});
+ editorState.apply(transaction);
+
+ allowMenuClose();
+ }
+
+ void preventMenuClose() {
+ widget.state.preventClose = true;
+ editorState.service.selectionService
+ .registerGestureInterceptor(gestureInterceptor);
+ }
+
+ void allowMenuClose() {
+ widget.state.preventClose = false;
+ editorState.service.selectionService
+ .unregisterGestureInterceptor(interceptorKey);
+ }
+
+ FlowySvgData iconFor(String alignment) {
+ switch (alignment) {
+ case leftAlignmentKey:
+ return FlowySvgs.align_left_s;
+ case rightAlignmentKey:
+ return FlowySvgs.align_right_s;
+ case centerAlignmentKey:
+ default:
+ return FlowySvgs.align_center_s;
+ }
+ }
+}
+
+class _AlignButtons extends StatelessWidget {
+ const _AlignButtons({required this.onAlignChanged});
+
+ final Function(String align) onAlignChanged;
+
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox(
+ height: 32,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const HSpace(4),
+ MenuBlockButton(
+ tooltip: LocaleKeys.document_plugins_optionAction_left,
+ iconData: FlowySvgs.align_left_s,
+ onTap: () => onAlignChanged(leftAlignmentKey),
+ ),
+ const _Divider(),
+ MenuBlockButton(
+ tooltip: LocaleKeys.document_plugins_optionAction_center,
+ iconData: FlowySvgs.align_center_s,
+ onTap: () => onAlignChanged(centerAlignmentKey),
+ ),
+ const _Divider(),
+ MenuBlockButton(
+ tooltip: LocaleKeys.document_plugins_optionAction_right,
+ iconData: FlowySvgs.align_right_s,
+ onTap: () => onAlignChanged(rightAlignmentKey),
+ ),
+ const HSpace(4),
+ ],
+ ),
+ );
+ }
+}
+
+class _Divider extends StatelessWidget {
+ const _Divider();
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.all(8),
+ child: Container(width: 1, color: Colors.grey),
+ );
+ }
+}
diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/video_placeholder.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/video_placeholder.dart
new file mode 100644
index 0000000000..a7d853b145
--- /dev/null
+++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/video/video_placeholder.dart
@@ -0,0 +1,136 @@
+import 'package:flutter/material.dart';
+
+import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
+import 'package:appflowy/plugins/document/application/prelude.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/video/upload_video_menu.dart';
+import 'package:appflowy/workspace/presentation/home/toast.dart';
+import 'package:appflowy_editor/appflowy_editor.dart' hide Log, UploadImageMenu;
+import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
+import 'package:appflowy_popover/appflowy_popover.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
+import 'package:flowy_infra_ui/style_widget/hover.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:go_router/go_router.dart';
+import 'package:string_validator/string_validator.dart';
+
+class VideoPlaceholder extends StatefulWidget {
+ const VideoPlaceholder({super.key, required this.node});
+
+ final Node node;
+
+ @override
+ State createState() => VideoPlaceholderState();
+}
+
+class VideoPlaceholderState extends State {
+ final controller = PopoverController();
+ final documentService = DocumentService();
+ late final editorState = context.read();
+
+ bool showLoading = false;
+
+ @override
+ Widget build(BuildContext context) {
+ final Widget child = DecoratedBox(
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.surfaceContainerHighest,
+ borderRadius: BorderRadius.circular(4),
+ ),
+ child: FlowyHover(
+ style: HoverStyle(borderRadius: BorderRadius.circular(4)),
+ child: SizedBox(
+ height: 52,
+ child: Row(
+ children: [
+ const HSpace(10),
+ const Icon(Icons.featured_video_outlined, size: 24),
+ const HSpace(10),
+ FlowyText(LocaleKeys.document_plugins_video_emptyLabel.tr()),
+ ],
+ ),
+ ),
+ ),
+ );
+
+ if (PlatformExtension.isDesktopOrWeb) {
+ return AppFlowyPopover(
+ controller: controller,
+ direction: PopoverDirection.bottomWithCenterAligned,
+ constraints: const BoxConstraints(
+ maxWidth: 540,
+ maxHeight: 360,
+ minHeight: 80,
+ ),
+ clickHandler: PopoverClickHandler.gestureDetector,
+ popupBuilder: (_) => UploadVideoMenu(
+ onUrlSubmitted: (url) {
+ controller.close();
+ WidgetsBinding.instance.addPostFrameCallback(
+ (_) async => updateSrc(url),
+ );
+ },
+ ),
+ child: child,
+ );
+ } else {
+ return MobileBlockActionButtons(
+ node: widget.node,
+ editorState: editorState,
+ child: GestureDetector(
+ onTap: () {
+ editorState.updateSelectionWithReason(null, extraInfo: {});
+ showUploadVideoMenu();
+ },
+ child: child,
+ ),
+ );
+ }
+ }
+
+ void showUploadVideoMenu() {
+ if (PlatformExtension.isDesktopOrWeb) {
+ controller.show();
+ } else {
+ showMobileBottomSheet(
+ context,
+ title: LocaleKeys.document_plugins_video_label.tr(),
+ showHeader: true,
+ showCloseButton: true,
+ showDragHandle: true,
+ builder: (context) => Container(
+ margin: const EdgeInsets.only(top: 12.0),
+ constraints: const BoxConstraints(
+ maxHeight: 340,
+ minHeight: 80,
+ ),
+ child: UploadVideoMenu(
+ onUrlSubmitted: (url) async {
+ context.pop();
+ await updateSrc(url);
+ },
+ ),
+ ),
+ );
+ }
+ }
+
+ Future updateSrc(String url) async {
+ if (url.isEmpty || !isURL(url)) {
+ // show error
+ showSnackBarMessage(
+ context,
+ LocaleKeys.document_imageBlock_error_invalidImage.tr(),
+ );
+ return;
+ }
+
+ final transaction = editorState.transaction;
+ transaction.updateNode(widget.node, {
+ VideoBlockKeys.url: url,
+ });
+ await editorState.apply(transaction);
+ }
+}
diff --git a/frontend/appflowy_flutter/lib/shared/patterns/common_patterns.dart b/frontend/appflowy_flutter/lib/shared/patterns/common_patterns.dart
index fce937908a..ea5da4f44a 100644
--- a/frontend/appflowy_flutter/lib/shared/patterns/common_patterns.dart
+++ b/frontend/appflowy_flutter/lib/shared/patterns/common_patterns.dart
@@ -13,6 +13,15 @@ const _imgUrlPattern =
r'(https?:\/\/)([^\s(["<,>/]*)(\/)[^\s[",><]*(.png|.jpg|.gif|.webm)(\?[^\s[",><]*)?';
final imgUrlRegex = RegExp(_imgUrlPattern);
+/// This pattern allows for both HTTP and HTTPS Scheme
+/// It allows for query parameters
+/// It only allows the following video extensions:
+/// .mp4, .mov, .avi, .webm, .flv, .m4v (mpeg), .mpeg, .h264,
+///
+const _videoUrlPattern =
+ r'(https?:\/\/)([^\s(["<,>/]*)(\/)[^\s[",><]*(.mp4|.mov|.avi|.webm|.flv|.m4v|.mpeg|.h264)(\?[^\s[",><]*)?';
+final videoUrlRegex = RegExp(_videoUrlPattern);
+
const _appflowyCloudUrlPattern = r'^(https:\/\/)(.*)(\.appflowy\.cloud\/)(.*)';
final appflowyCloudUrlRegex = RegExp(_appflowyCloudUrlPattern);
diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock
index dab9ec0475..bb49c0b84d 100644
--- a/frontend/appflowy_flutter/pubspec.lock
+++ b/frontend/appflowy_flutter/pubspec.lock
@@ -62,10 +62,10 @@ packages:
dependency: "direct main"
description:
name: appflowy_editor_plugins
- sha256: "9d91f65e564f85ffc98a407524371beeb1fd40aabd621b00ba8a722058636094"
+ sha256: "46c899acc22245798e5beed255852455d9d85c3fae8b275ef4db257810b1c59d"
url: "https://pub.dev"
source: hosted
- version: "0.0.2"
+ version: "0.0.6"
appflowy_popover:
dependency: "direct main"
description:
@@ -868,6 +868,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
+ image:
+ dependency: transitive
+ description:
+ name: image
+ sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.1.7"
image_gallery_saver:
dependency: "direct main"
description:
@@ -1145,6 +1153,78 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.8.0"
+ media_kit:
+ dependency: transitive
+ description:
+ name: media_kit
+ sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.10+1"
+ media_kit_libs_android_video:
+ dependency: transitive
+ description:
+ name: media_kit_libs_android_video
+ sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.6"
+ media_kit_libs_ios_video:
+ dependency: transitive
+ description:
+ name: media_kit_libs_ios_video
+ sha256: b5382994eb37a4564c368386c154ad70ba0cc78dacdd3fb0cd9f30db6d837991
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.4"
+ media_kit_libs_linux:
+ dependency: transitive
+ description:
+ name: media_kit_libs_linux
+ sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.3"
+ media_kit_libs_macos_video:
+ dependency: transitive
+ description:
+ name: media_kit_libs_macos_video
+ sha256: f26aa1452b665df288e360393758f84b911f70ffb3878032e1aabba23aa1032d
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.4"
+ media_kit_libs_video:
+ dependency: transitive
+ description:
+ name: media_kit_libs_video
+ sha256: "3688e0c31482074578652bf038ce6301a5d21e1eda6b54fc3117ffeb4bdba067"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
+ media_kit_libs_windows_video:
+ dependency: transitive
+ description:
+ name: media_kit_libs_windows_video
+ sha256: "7bace5f35d9afcc7f9b5cdadb7541d2191a66bb3fc71bfa11c1395b3360f6122"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.9"
+ media_kit_native_event_loop:
+ dependency: transitive
+ description:
+ name: media_kit_native_event_loop
+ sha256: a605cf185499d14d58935b8784955a92a4bf0ff4e19a23de3d17a9106303930e
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.8"
+ media_kit_video:
+ dependency: transitive
+ description:
+ name: media_kit_video
+ sha256: c048d11a19e379aebbe810647636e3fc6d18374637e2ae12def4ff8a4b99a882
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.4"
meta:
dependency: transitive
description:
@@ -1521,6 +1601,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.27.7"
+ safe_local_storage:
+ dependency: transitive
+ description:
+ name: safe_local_storage
+ sha256: ede4eb6cb7d88a116b3d3bf1df70790b9e2038bc37cb19112e381217c74d9440
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.2"
scaled_app:
dependency: "direct main"
description:
@@ -1529,6 +1617,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.0"
+ screen_brightness:
+ dependency: transitive
+ description:
+ name: screen_brightness
+ sha256: ed8da4a4511e79422fc1aa88138e920e4008cd312b72cdaa15ccb426c0faaedd
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.2+1"
+ screen_brightness_android:
+ dependency: transitive
+ description:
+ name: screen_brightness_android
+ sha256: "3df10961e3a9e968a5e076fe27e7f4741fa8a1d3950bdeb48cf121ed529d0caf"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.0+2"
+ screen_brightness_ios:
+ dependency: transitive
+ description:
+ name: screen_brightness_ios
+ sha256: "99adc3ca5490b8294284aad5fcc87f061ad685050e03cf45d3d018fe398fd9a2"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.0"
+ screen_brightness_macos:
+ dependency: transitive
+ description:
+ name: screen_brightness_macos
+ sha256: "64b34e7e3f4900d7687c8e8fb514246845a73ecec05ab53483ed025bd4a899fd"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.0+1"
+ screen_brightness_platform_interface:
+ dependency: transitive
+ description:
+ name: screen_brightness_platform_interface
+ sha256: b211d07f0c96637a15fb06f6168617e18030d5d74ad03795dd8547a52717c171
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.0"
+ screen_brightness_windows:
+ dependency: transitive
+ description:
+ name: screen_brightness_windows
+ sha256: "9261bf33d0fc2707d8cf16339ce25768100a65e70af0fcabaf032fc12408ba86"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.3"
screen_retriever:
dependency: transitive
description:
@@ -1968,6 +2104,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.0"
+ uri_parser:
+ dependency: transitive
+ description:
+ name: uri_parser
+ sha256: "6543c9fd86d2862fac55d800a43e67c0dcd1a41677cb69c2f8edfe73bbcf1835"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
url_launcher:
dependency: "direct main"
description:
@@ -2105,6 +2249,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "14.2.1"
+ volume_controller:
+ dependency: transitive
+ description:
+ name: volume_controller
+ sha256: "189bdc7a554f476b412e4c8b2f474562b09d74bc458c23667356bce3ca1d48c9"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.7"
+ wakelock_plus:
+ dependency: transitive
+ description:
+ name: wakelock_plus
+ sha256: "104d94837bb28c735894dcd592877e990149c380e6358b00c04398ca1426eed4"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ wakelock_plus_platform_interface:
+ dependency: transitive
+ description:
+ name: wakelock_plus_platform_interface
+ sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
watcher:
dependency: transitive
description:
diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml
index 35050161f7..0ffe803751 100644
--- a/frontend/appflowy_flutter/pubspec.yaml
+++ b/frontend/appflowy_flutter/pubspec.yaml
@@ -47,7 +47,7 @@ dependencies:
ref: 8a6434ae3d02624b614a010af80f775db11bf22e
appflowy_result:
path: packages/appflowy_result
- appflowy_editor_plugins: ^0.0.2
+ appflowy_editor_plugins: ^0.0.6
appflowy_editor:
diff --git a/frontend/resources/flowy_icons/16x/m_add_block_video.svg b/frontend/resources/flowy_icons/16x/m_add_block_video.svg
new file mode 100644
index 0000000000..5bd19d0a3e
--- /dev/null
+++ b/frontend/resources/flowy_icons/16x/m_add_block_video.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json
index 04ab72f795..768a5d804a 100644
--- a/frontend/resources/translations/en.json
+++ b/frontend/resources/translations/en.json
@@ -1121,7 +1121,16 @@
"newDatabase": "New Database",
"linkToDatabase": "Link to Database"
},
- "date": "Date"
+ "date": "Date",
+ "video": {
+ "label": "Video",
+ "emptyLabel": "Add a video",
+ "placeholder": "Enter a link to a video",
+ "copiedToPasteBoard": "The video link has been copied to the clipboard",
+ "insertVideo": "Insert video",
+ "invalidVideoUrl": "Invalid video url, must be a valid file.",
+ "supportedFormats": "Supported formats: MP4, WebM, MOV, AVI, FLV, MPEG/M4V, H.264"
+ }
},
"outlineBlock": {
"placeholder": "Table of Contents"
diff --git a/frontend/scripts/docker-buildfiles/Dockerfile b/frontend/scripts/docker-buildfiles/Dockerfile
index 8aad410e94..8ebe5fc8ef 100644
--- a/frontend/scripts/docker-buildfiles/Dockerfile
+++ b/frontend/scripts/docker-buildfiles/Dockerfile
@@ -48,7 +48,7 @@ RUN dart pub global activate protoc_plugin 21.1.2
# Install build dependencies for AppFlowy
RUN yay -S --noconfirm jemalloc4 cargo-make cargo-binstall
-RUN sudo pacman -S --noconfirm git libkeybinder3 sqlite clang rsync libnotify rocksdb zstd
+RUN sudo pacman -S --noconfirm git libkeybinder3 sqlite clang rsync libnotify rocksdb zstd mpv
RUN sudo ln -s /usr/bin/sha1sum /usr/bin/shasum
RUN source ~/.cargo/env && cargo binstall duckscript_cli -y
diff --git a/frontend/scripts/install_dev_env/install_linux.sh b/frontend/scripts/install_dev_env/install_linux.sh
index 22b491321b..b02b31d62c 100755
--- a/frontend/scripts/install_dev_env/install_linux.sh
+++ b/frontend/scripts/install_dev_env/install_linux.sh
@@ -78,7 +78,17 @@ if command apt-get &>/dev/null; then
elif command dnf &>/dev/null; then
sudo dnf install libnotify-dev
else
- echo 'Your system is not supported, please install libnotify manually.'
+ echo 'Your system is not supported, please install libnotify-dev manually.'
+fi
+
+# For Video Block support
+printMessage "Installing libmpv-dev mpv"
+if command apt-get &>/dev/null; then
+ sudo apt-get install libmpv-dev mpv
+elif command dnf &>/dev/null; then
+ sudo dnf install libmpv-dev mpv
+else
+ echo 'Your system is not supported, please install libmpv-dev mpv manually.'
fi
# Add the githooks directory to your git configuration
diff --git a/frontend/scripts/linux_distribution/appimage/AppImageBuilder.yml b/frontend/scripts/linux_distribution/appimage/AppImageBuilder.yml
index c205814401..5049ff5eb3 100644
--- a/frontend/scripts/linux_distribution/appimage/AppImageBuilder.yml
+++ b/frontend/scripts/linux_distribution/appimage/AppImageBuilder.yml
@@ -19,47 +19,55 @@ AppDir:
exec_args: $@
apt:
arch:
- - amd64
+ - amd64
allow_unauthenticated: true
sources:
- - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy main restricted
- - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
- - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy universe
- - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates universe
- - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy multiverse
- - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
- - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
- universe multiverse
- - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
- - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
- - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
- - sourceline: deb https://ppa.launchpadcontent.net/touchegg/stable/ubuntu/ jammy
- main
- - sourceline: deb https://packagecloud.io/slacktechnologies/slack/debian/ jessie
- main
- - sourceline: deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg]
- https://cli.github.com/packages stable main
- - sourceline: deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_16.x
- jammy main
- - sourceline: deb [arch=amd64,arm64,armhf] http://packages.microsoft.com/repos/code
- stable main
- - sourceline: deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable
- main
+ - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy main restricted
+ - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
+ - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy universe
+ - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates universe
+ - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy multiverse
+ - sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
+ - sourceline:
+ deb http://id.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
+ universe multiverse
+ - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
+ - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
+ - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
+ - sourceline:
+ deb https://ppa.launchpadcontent.net/touchegg/stable/ubuntu/ jammy
+ main
+ - sourceline:
+ deb https://packagecloud.io/slacktechnologies/slack/debian/ jessie
+ main
+ - sourceline:
+ deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg]
+ https://cli.github.com/packages stable main
+ - sourceline:
+ deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_16.x
+ jammy main
+ - sourceline:
+ deb [arch=amd64,arm64,armhf] http://packages.microsoft.com/repos/code
+ stable main
+ - sourceline:
+ deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable
+ main
include:
- - libc6:amd64
- - libnotify4:amd64
- - libkeybinder-3.0-0:amd64
- - libwayland-cursor0:amd64
- - libwayland-client0:amd64
- - libwayland-egl1:amd64
+ - libc6:amd64
+ - libnotify4:amd64
+ - libkeybinder-3.0-0:amd64
+ - libwayland-cursor0:amd64
+ - libwayland-client0:amd64
+ - libwayland-egl1:amd64
+ - mpv:amd64
files:
include: []
exclude:
- - usr/share/man
- - usr/share/doc/*/README.*
- - usr/share/doc/*/changelog.*
- - usr/share/doc/*/NEWS.*
- - usr/share/doc/*/TODO.*
+ - usr/share/man
+ - usr/share/doc/*/README.*
+ - usr/share/doc/*/changelog.*
+ - usr/share/doc/*/NEWS.*
+ - usr/share/doc/*/TODO.*
test:
fedora-30:
image: appimagecrafters/tests-env:fedora-30
@@ -78,4 +86,4 @@ AppDir:
command: ./AppRun
AppImage:
arch: x86_64
- update-information: guess
\ No newline at end of file
+ update-information: guess