mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: video block support (#5199)
* feat: video block support * chore: workaround for ci failing * chore: test * chore: check status * chore: revert apt-get * chore: add mpv * chore: add mpv to appimagebuilder * chore: try again * chore: update after merge * ci: remove workaround for microsoft issue * chore: update editor plugins * feat: add video block option on mobile * fix: final changes for menu * chore: undo cocoapods version
This commit is contained in:
22
.github/workflows/flutter_ci.yaml
vendored
22
.github/workflows/flutter_ci.yaml
vendored
@ -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/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 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 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
|
fi
|
||||||
shell: bash
|
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/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 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 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
|
shell: bash
|
||||||
|
|
||||||
- name: Enable Flutter Desktop
|
- name: Enable Flutter Desktop
|
||||||
@ -319,6 +319,12 @@ jobs:
|
|||||||
- name: Checkout source code
|
- name: Checkout source code
|
||||||
uses: actions/checkout@v4
|
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
|
- name: Flutter Integration Test 1
|
||||||
uses: ./.github/actions/flutter_integration_test
|
uses: ./.github/actions/flutter_integration_test
|
||||||
with:
|
with:
|
||||||
@ -343,6 +349,12 @@ jobs:
|
|||||||
- name: Checkout source code
|
- name: Checkout source code
|
||||||
uses: actions/checkout@v4
|
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
|
- name: Flutter Integration Test 2
|
||||||
uses: ./.github/actions/flutter_integration_test
|
uses: ./.github/actions/flutter_integration_test
|
||||||
with:
|
with:
|
||||||
@ -367,6 +379,12 @@ jobs:
|
|||||||
- name: Checkout source code
|
- name: Checkout source code
|
||||||
uses: actions/checkout@v4
|
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
|
- name: Flutter Integration Test 3
|
||||||
uses: ./.github/actions/flutter_integration_test
|
uses: ./.github/actions/flutter_integration_test
|
||||||
with:
|
with:
|
||||||
|
@ -58,4 +58,11 @@
|
|||||||
<action android:name="android.support.customtabs.action.CustomTabsService" />
|
<action android:name="android.support.customtabs.action.CustomTabsService" />
|
||||||
</intent>
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
|
<!--
|
||||||
|
Media access permissions.
|
||||||
|
Android 13 or higher.
|
||||||
|
Used for VideoBlock (edia_kit)
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
</manifest>
|
</manifest>
|
@ -58,6 +58,12 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- keyboard_height_plugin (0.0.1):
|
- keyboard_height_plugin (0.0.1):
|
||||||
- Flutter
|
- 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):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
@ -66,6 +72,8 @@ PODS:
|
|||||||
- permission_handler_apple (9.3.0):
|
- permission_handler_apple (9.3.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- ReachabilitySwift (5.0.0)
|
- ReachabilitySwift (5.0.0)
|
||||||
|
- screen_brightness_ios (0.1.0):
|
||||||
|
- Flutter
|
||||||
- SDWebImage (5.14.2):
|
- SDWebImage (5.14.2):
|
||||||
- SDWebImage/Core (= 5.14.2)
|
- SDWebImage/Core (= 5.14.2)
|
||||||
- SDWebImage/Core (5.14.2)
|
- SDWebImage/Core (5.14.2)
|
||||||
@ -83,6 +91,10 @@ PODS:
|
|||||||
- Toast (4.0.0)
|
- Toast (4.0.0)
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- volume_controller (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- wakelock_plus (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
- app_links (from `.symlinks/plugins/app_links/ios`)
|
||||||
@ -98,14 +110,20 @@ DEPENDENCIES:
|
|||||||
- integration_test (from `.symlinks/plugins/integration_test/ios`)
|
- integration_test (from `.symlinks/plugins/integration_test/ios`)
|
||||||
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
|
- irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`)
|
||||||
- keyboard_height_plugin (from `.symlinks/plugins/keyboard_height_plugin/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`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- 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`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
||||||
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
|
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/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:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
@ -143,12 +161,20 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/irondash_engine_context/ios"
|
:path: ".symlinks/plugins/irondash_engine_context/ios"
|
||||||
keyboard_height_plugin:
|
keyboard_height_plugin:
|
||||||
:path: ".symlinks/plugins/keyboard_height_plugin/ios"
|
: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:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
|
screen_brightness_ios:
|
||||||
|
:path: ".symlinks/plugins/screen_brightness_ios/ios"
|
||||||
share_plus:
|
share_plus:
|
||||||
:path: ".symlinks/plugins/share_plus/ios"
|
:path: ".symlinks/plugins/share_plus/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
@ -159,6 +185,10 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/super_native_extensions/ios"
|
:path: ".symlinks/plugins/super_native_extensions/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
:path: ".symlinks/plugins/url_launcher_ios/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:
|
SPEC CHECKSUMS:
|
||||||
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
|
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
|
||||||
@ -176,10 +206,14 @@ SPEC CHECKSUMS:
|
|||||||
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
|
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
|
||||||
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
|
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
|
||||||
keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86
|
keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86
|
||||||
|
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||||
|
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
||||||
|
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||||
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||||
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
|
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
|
||||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||||
|
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
||||||
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
|
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
|
||||||
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
|
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
|
||||||
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
||||||
@ -188,6 +222,8 @@ SPEC CHECKSUMS:
|
|||||||
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
|
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
|
||||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||||
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
|
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
|
||||||
|
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
||||||
|
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||||
|
|
||||||
PODFILE CHECKSUM: d0d9b4ff572d8695c38eb3f9b490f55cdfc57eca
|
PODFILE CHECKSUM: d0d9b4ff572d8695c38eb3f9b490f55cdfc57eca
|
||||||
|
|
||||||
|
@ -66,5 +66,10 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false />
|
<false />
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
@ -1,9 +1,12 @@
|
|||||||
import 'package:scaled_app/scaled_app.dart';
|
import 'package:scaled_app/scaled_app.dart';
|
||||||
|
|
||||||
|
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
||||||
|
|
||||||
import 'startup/startup.dart';
|
import 'startup/startup.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
ScaledWidgetsFlutterBinding.ensureInitialized(scaleFactor: (_) => 1.0);
|
ScaledWidgetsFlutterBinding.ensureInitialized(scaleFactor: (_) => 1.0);
|
||||||
|
VideoBlockKit.ensureInitialized();
|
||||||
|
|
||||||
await runAppFlowy();
|
await runAppFlowy();
|
||||||
}
|
}
|
||||||
|
@ -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/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/image/custom_image_block_component.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.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/plugins/document/presentation/editor_style.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
||||||
@ -110,7 +112,7 @@ Map<String, BlockComponentBuilder> getEditorBuilderMap({
|
|||||||
showMenu: true,
|
showMenu: true,
|
||||||
menuBuilder: (Node node, CustomImageBlockComponentState state) =>
|
menuBuilder: (Node node, CustomImageBlockComponentState state) =>
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 0,
|
top: 10,
|
||||||
right: 10,
|
right: 10,
|
||||||
child: ImageMenu(node: node, state: state),
|
child: ImageMenu(node: node, state: state),
|
||||||
),
|
),
|
||||||
@ -180,7 +182,6 @@ Map<String, BlockComponentBuilder> getEditorBuilderMap({
|
|||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
),
|
),
|
||||||
CodeBlockKeys.type: CodeBlockComponentBuilder(
|
CodeBlockKeys.type: CodeBlockComponentBuilder(
|
||||||
editorState: editorState,
|
|
||||||
configuration: configuration.copyWith(
|
configuration: configuration.copyWith(
|
||||||
textStyle: (_) => styleCustomizer.codeBlockStyleBuilder(),
|
textStyle: (_) => styleCustomizer.codeBlockStyleBuilder(),
|
||||||
placeholderTextStyle: (_) => styleCustomizer.codeBlockStyleBuilder(),
|
placeholderTextStyle: (_) => styleCustomizer.codeBlockStyleBuilder(),
|
||||||
@ -228,6 +229,16 @@ Map<String, BlockComponentBuilder> getEditorBuilderMap({
|
|||||||
errorBlockComponentBuilderKey: ErrorBlockComponentBuilder(
|
errorBlockComponentBuilderKey: ErrorBlockComponentBuilder(
|
||||||
configuration: configuration,
|
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 = {
|
final builders = {
|
||||||
|
@ -388,6 +388,7 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
|||||||
emojiMenuItem,
|
emojiMenuItem,
|
||||||
autoGeneratorMenuItem,
|
autoGeneratorMenuItem,
|
||||||
dateMenuItem,
|
dateMenuItem,
|
||||||
|
videoBlockItem(LocaleKeys.document_plugins_video_label.tr()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/mobile/presentation/widgets/widgets.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/workspace/presentation/home/toast.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart' hide ResizableImage;
|
import 'package:appflowy_editor/appflowy_editor.dart' hide ResizableImage;
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:string_validator/string_validator.dart';
|
import 'package:string_validator/string_validator.dart';
|
||||||
@ -109,10 +110,7 @@ class CustomImageBlockComponentBuilder extends BlockComponentBuilder {
|
|||||||
node: node,
|
node: node,
|
||||||
showActions: showActions(node),
|
showActions: showActions(node),
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
actionBuilder: (context, state) => actionBuilder(
|
actionBuilder: (_, state) => actionBuilder(blockComponentContext, state),
|
||||||
blockComponentContext,
|
|
||||||
state,
|
|
||||||
),
|
|
||||||
showMenu: showMenu,
|
showMenu: showMenu,
|
||||||
menuBuilder: menuBuilder,
|
menuBuilder: menuBuilder,
|
||||||
);
|
);
|
||||||
|
@ -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
|
// date
|
||||||
TypeOptionMenuItemValue(
|
TypeOptionMenuItemValue(
|
||||||
value: ParagraphBlockKeys.type,
|
value: ParagraphBlockKeys.type,
|
||||||
@ -287,6 +296,7 @@ class _AddBlockMenu extends StatelessWidget {
|
|||||||
NumberedListBlockKeys.type: const Color(0xFFA35F94),
|
NumberedListBlockKeys.type: const Color(0xFFA35F94),
|
||||||
ToggleListBlockKeys.type: const Color(0xFFA35F94),
|
ToggleListBlockKeys.type: const Color(0xFFA35F94),
|
||||||
ImageBlockKeys.type: const Color(0xFFBAAC74),
|
ImageBlockKeys.type: const Color(0xFFBAAC74),
|
||||||
|
VideoBlockKeys.type: const Color(0xFFBAAC74),
|
||||||
MentionBlockKeys.type: const Color(0xFF40AAB8),
|
MentionBlockKeys.type: const Color(0xFF40AAB8),
|
||||||
DividerBlockKeys.type: const Color(0xFF4BB299),
|
DividerBlockKeys.type: const Color(0xFF4BB299),
|
||||||
CalloutBlockKeys.type: const Color(0xFF66599B),
|
CalloutBlockKeys.type: const Color(0xFF66599B),
|
||||||
@ -303,6 +313,7 @@ class _AddBlockMenu extends StatelessWidget {
|
|||||||
NumberedListBlockKeys.type: const Color(0xFFFFB9EF),
|
NumberedListBlockKeys.type: const Color(0xFFFFB9EF),
|
||||||
ToggleListBlockKeys.type: const Color(0xFFFFB9EF),
|
ToggleListBlockKeys.type: const Color(0xFFFFB9EF),
|
||||||
ImageBlockKeys.type: const Color(0xFFFDEDA7),
|
ImageBlockKeys.type: const Color(0xFFFDEDA7),
|
||||||
|
VideoBlockKeys.type: const Color(0xFFFDEDA7),
|
||||||
MentionBlockKeys.type: const Color(0xFF91EAF5),
|
MentionBlockKeys.type: const Color(0xFF91EAF5),
|
||||||
DividerBlockKeys.type: const Color(0xFF98F4CD),
|
DividerBlockKeys.type: const Color(0xFF98F4CD),
|
||||||
CalloutBlockKeys.type: const Color(0xFFCABDFF),
|
CalloutBlockKeys.type: const Color(0xFFCABDFF),
|
||||||
|
@ -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<UploadVideoMenu> createState() => _UploadVideoMenuState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UploadVideoMenuState extends State<UploadVideoMenu> {
|
||||||
|
@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);
|
||||||
|
}
|
@ -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<VideoMenu> createState() => _VideoMenuState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoMenuState extends State<VideoMenu> {
|
||||||
|
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<EditorState>()
|
||||||
|
..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<ClipboardService>().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<void> deleteVideo() async {
|
||||||
|
final node = widget.node;
|
||||||
|
final editorState = context.read<EditorState>();
|
||||||
|
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<EditorState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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<VideoPlaceholder> createState() => VideoPlaceholderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class VideoPlaceholderState extends State<VideoPlaceholder> {
|
||||||
|
final controller = PopoverController();
|
||||||
|
final documentService = DocumentService();
|
||||||
|
late final editorState = context.read<EditorState>();
|
||||||
|
|
||||||
|
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<void> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,15 @@ const _imgUrlPattern =
|
|||||||
r'(https?:\/\/)([^\s(["<,>/]*)(\/)[^\s[",><]*(.png|.jpg|.gif|.webm)(\?[^\s[",><]*)?';
|
r'(https?:\/\/)([^\s(["<,>/]*)(\/)[^\s[",><]*(.png|.jpg|.gif|.webm)(\?[^\s[",><]*)?';
|
||||||
final imgUrlRegex = RegExp(_imgUrlPattern);
|
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\/)(.*)';
|
const _appflowyCloudUrlPattern = r'^(https:\/\/)(.*)(\.appflowy\.cloud\/)(.*)';
|
||||||
final appflowyCloudUrlRegex = RegExp(_appflowyCloudUrlPattern);
|
final appflowyCloudUrlRegex = RegExp(_appflowyCloudUrlPattern);
|
||||||
|
|
||||||
|
@ -62,10 +62,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: appflowy_editor_plugins
|
name: appflowy_editor_plugins
|
||||||
sha256: "9d91f65e564f85ffc98a407524371beeb1fd40aabd621b00ba8a722058636094"
|
sha256: "46c899acc22245798e5beed255852455d9d85c3fae8b275ef4db257810b1c59d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.2"
|
version: "0.0.6"
|
||||||
appflowy_popover:
|
appflowy_popover:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -868,6 +868,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
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:
|
image_gallery_saver:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1145,6 +1153,78 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.0"
|
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:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1521,6 +1601,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.27.7"
|
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:
|
scaled_app:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1529,6 +1617,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
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:
|
screen_retriever:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1968,6 +2104,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
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:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -2105,6 +2249,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.1"
|
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:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -47,7 +47,7 @@ dependencies:
|
|||||||
ref: 8a6434ae3d02624b614a010af80f775db11bf22e
|
ref: 8a6434ae3d02624b614a010af80f775db11bf22e
|
||||||
appflowy_result:
|
appflowy_result:
|
||||||
path: packages/appflowy_result
|
path: packages/appflowy_result
|
||||||
appflowy_editor_plugins: ^0.0.2
|
appflowy_editor_plugins: ^0.0.6
|
||||||
|
|
||||||
appflowy_editor:
|
appflowy_editor:
|
||||||
|
|
||||||
|
2
frontend/resources/flowy_icons/16x/m_add_block_video.svg
Normal file
2
frontend/resources/flowy_icons/16x/m_add_block_video.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#e8eaed"><path d="m384-312 264-168-264-168v336ZM168-192q-29.7 0-50.85-21.16Q96-234.32 96-264.04v-432.24Q96-726 117.15-747T168-768h624q29.7 0 50.85 21.16Q864-725.68 864-695.96v432.24Q864-234 842.85-213T792-192H168Zm0-72h624v-432H168v432Zm0 0v-432 432Z"/></svg>
|
After Width: | Height: | Size: 358 B |
@ -1121,7 +1121,16 @@
|
|||||||
"newDatabase": "New Database",
|
"newDatabase": "New Database",
|
||||||
"linkToDatabase": "Link to 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": {
|
"outlineBlock": {
|
||||||
"placeholder": "Table of Contents"
|
"placeholder": "Table of Contents"
|
||||||
|
@ -48,7 +48,7 @@ RUN dart pub global activate protoc_plugin 21.1.2
|
|||||||
|
|
||||||
# Install build dependencies for AppFlowy
|
# Install build dependencies for AppFlowy
|
||||||
RUN yay -S --noconfirm jemalloc4 cargo-make cargo-binstall
|
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 sudo ln -s /usr/bin/sha1sum /usr/bin/shasum
|
||||||
RUN source ~/.cargo/env && cargo binstall duckscript_cli -y
|
RUN source ~/.cargo/env && cargo binstall duckscript_cli -y
|
||||||
|
|
||||||
|
@ -78,7 +78,17 @@ if command apt-get &>/dev/null; then
|
|||||||
elif command dnf &>/dev/null; then
|
elif command dnf &>/dev/null; then
|
||||||
sudo dnf install libnotify-dev
|
sudo dnf install libnotify-dev
|
||||||
else
|
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
|
fi
|
||||||
|
|
||||||
# Add the githooks directory to your git configuration
|
# Add the githooks directory to your git configuration
|
||||||
|
@ -28,22 +28,29 @@ AppDir:
|
|||||||
- sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates 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 multiverse
|
||||||
- sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
|
- sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
|
||||||
- sourceline: deb http://id.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
|
- sourceline:
|
||||||
|
deb http://id.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
|
||||||
universe multiverse
|
universe multiverse
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
|
- 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 universe
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
|
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
|
||||||
- sourceline: deb https://ppa.launchpadcontent.net/touchegg/stable/ubuntu/ jammy
|
- sourceline:
|
||||||
|
deb https://ppa.launchpadcontent.net/touchegg/stable/ubuntu/ jammy
|
||||||
main
|
main
|
||||||
- sourceline: deb https://packagecloud.io/slacktechnologies/slack/debian/ jessie
|
- sourceline:
|
||||||
|
deb https://packagecloud.io/slacktechnologies/slack/debian/ jessie
|
||||||
main
|
main
|
||||||
- sourceline: deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg]
|
- sourceline:
|
||||||
|
deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg]
|
||||||
https://cli.github.com/packages stable main
|
https://cli.github.com/packages stable main
|
||||||
- sourceline: deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_16.x
|
- sourceline:
|
||||||
|
deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_16.x
|
||||||
jammy main
|
jammy main
|
||||||
- sourceline: deb [arch=amd64,arm64,armhf] http://packages.microsoft.com/repos/code
|
- sourceline:
|
||||||
|
deb [arch=amd64,arm64,armhf] http://packages.microsoft.com/repos/code
|
||||||
stable main
|
stable main
|
||||||
- sourceline: deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable
|
- sourceline:
|
||||||
|
deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable
|
||||||
main
|
main
|
||||||
include:
|
include:
|
||||||
- libc6:amd64
|
- libc6:amd64
|
||||||
@ -52,6 +59,7 @@ AppDir:
|
|||||||
- libwayland-cursor0:amd64
|
- libwayland-cursor0:amd64
|
||||||
- libwayland-client0:amd64
|
- libwayland-client0:amd64
|
||||||
- libwayland-egl1:amd64
|
- libwayland-egl1:amd64
|
||||||
|
- mpv:amd64
|
||||||
files:
|
files:
|
||||||
include: []
|
include: []
|
||||||
exclude:
|
exclude:
|
||||||
|
Reference in New Issue
Block a user