mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: launch review 0.5.9 (#5443)
* fix: lose focus in editor on open settings dialog * fix: support CTRL+. for sidebar toggle * fix: make notify method private * fix: copy for video block * fix: copy for notification setting * fix: add libmpv to appimage builder * fix: missing tabs bloc from context * ci: add libmpv-dev to missing workflows * fix: do not depend on inherited widget in dispose * test: add media kit ensureInitialized to integration tests * fix: use maybeOf for AFFocusManager * fix: use pattern matching for youtube error * fix: missed null-promise on convertion
This commit is contained in:
parent
2c0cdfa6c5
commit
4ad7c48b25
2
.github/actions/flutter_build/action.yml
vendored
2
.github/actions/flutter_build/action.yml
vendored
@ -63,7 +63,7 @@ runs:
|
|||||||
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
|
||||||
elif [ "$RUNNER_OS" == "Windows" ]; then
|
elif [ "$RUNNER_OS" == "Windows" ]; then
|
||||||
vcpkg integrate install
|
vcpkg integrate install
|
||||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||||
|
@ -52,7 +52,7 @@ runs:
|
|||||||
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 network-manager
|
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 network-manager libmpv-dev mpv
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Enable Flutter Desktop
|
- name: Enable Flutter Desktop
|
||||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -367,8 +367,8 @@ 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 apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
|
sudo apt-get install -y build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
|
||||||
sudo apt-get install keybinder-3.0 libnotify-dev
|
sudo apt-get install keybinder-3.0
|
||||||
sudo apt-get -y install alien
|
sudo apt-get install -y alien libnotify-dev libmpv-dev mpv
|
||||||
source $HOME/.cargo/env
|
source $HOME/.cargo/env
|
||||||
cargo install --force cargo-make
|
cargo install --force cargo-make
|
||||||
cargo install --force duckscript_cli
|
cargo install --force duckscript_cli
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
@ -36,6 +37,8 @@ extension AppFlowyTestBase on WidgetTester {
|
|||||||
AuthenticatorType? cloudType,
|
AuthenticatorType? cloudType,
|
||||||
String? email,
|
String? email,
|
||||||
}) async {
|
}) async {
|
||||||
|
VideoBlockKit.ensureInitialized();
|
||||||
|
|
||||||
if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) {
|
if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) {
|
||||||
// Set the window size
|
// Set the window size
|
||||||
await binding.setSurfaceSize(windowSize);
|
await binding.setSurfaceSize(windowSize);
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
|
||||||
@ -20,6 +23,7 @@ import 'package:appflowy/plugins/inline_actions/inline_actions_service.dart';
|
|||||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/shortcuts/settings_shortcuts_service.dart';
|
import 'package:appflowy/workspace/application/settings/shortcuts/settings_shortcuts_service.dart';
|
||||||
import 'package:appflowy/workspace/application/view_info/view_info_bloc.dart';
|
import 'package:appflowy/workspace/application/view_info/view_info_bloc.dart';
|
||||||
|
import 'package:appflowy/workspace/presentation/home/af_focus_manager.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.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';
|
||||||
@ -27,8 +31,6 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
final codeBlockLocalization = CodeBlockLocalizations(
|
final codeBlockLocalization = CodeBlockLocalizations(
|
||||||
@ -211,6 +213,10 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
|||||||
style: styleCustomizer.selectionMenuStyleBuilder(),
|
style: styleCustomizer.selectionMenuStyleBuilder(),
|
||||||
).handler(editorState);
|
).handler(editorState);
|
||||||
|
|
||||||
|
AFFocusManager? focusManager;
|
||||||
|
|
||||||
|
void _loseFocus() => widget.editorState.selection = null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -251,17 +257,35 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
|||||||
// customize the dynamic theme color
|
// customize the dynamic theme color
|
||||||
_customizeBlockComponentBackgroundColorDecorator();
|
_customizeBlockComponentBackgroundColorDecorator();
|
||||||
|
|
||||||
if (widget.initialSelection != null) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
if (!mounted) {
|
||||||
widget.editorState.updateSelectionWithReason(
|
return;
|
||||||
widget.initialSelection,
|
}
|
||||||
);
|
|
||||||
});
|
focusManager = AFFocusManager.maybeOf(context);
|
||||||
|
focusManager?.loseFocusNotifier.addListener(_loseFocus);
|
||||||
|
|
||||||
|
if (widget.initialSelection != null) {
|
||||||
|
widget.editorState.updateSelectionWithReason(widget.initialSelection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
final currFocusManager = AFFocusManager.maybeOf(context);
|
||||||
|
if (focusManager != currFocusManager) {
|
||||||
|
focusManager?.loseFocusNotifier.removeListener(_loseFocus);
|
||||||
|
focusManager = currFocusManager;
|
||||||
|
focusManager?.loseFocusNotifier.addListener(_loseFocus);
|
||||||
}
|
}
|
||||||
|
super.didChangeDependencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
focusManager?.loseFocusNotifier.removeListener(_loseFocus);
|
||||||
|
|
||||||
if (widget.useViewInfoBloc && !viewInfoBloc.isClosed) {
|
if (widget.useViewInfoBloc && !viewInfoBloc.isClosed) {
|
||||||
viewInfoBloc.add(const ViewInfoEvent.unregisterEditorState());
|
viewInfoBloc.add(const ViewInfoEvent.unregisterEditorState());
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ class _EmbedUrl extends StatefulWidget {
|
|||||||
|
|
||||||
class _EmbedUrlState extends State<_EmbedUrl> {
|
class _EmbedUrlState extends State<_EmbedUrl> {
|
||||||
bool isUrlValid = true;
|
bool isUrlValid = true;
|
||||||
|
bool isYouTubeError = false;
|
||||||
String inputText = '';
|
String inputText = '';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -60,11 +61,18 @@ class _EmbedUrlState extends State<_EmbedUrl> {
|
|||||||
if (!isUrlValid) ...[
|
if (!isUrlValid) ...[
|
||||||
const VSpace(8),
|
const VSpace(8),
|
||||||
FlowyText(
|
FlowyText(
|
||||||
LocaleKeys.document_plugins_video_invalidVideoUrl.tr(),
|
isYouTubeError
|
||||||
|
? LocaleKeys.document_plugins_video_invalidVideoUrlYouTube.tr()
|
||||||
|
: LocaleKeys.document_plugins_video_invalidVideoUrl.tr(),
|
||||||
color: Theme.of(context).colorScheme.error,
|
color: Theme.of(context).colorScheme.error,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const VSpace(8),
|
const VSpace(8),
|
||||||
|
FlowyText(
|
||||||
|
LocaleKeys.document_plugins_video_supportedFormats.tr(),
|
||||||
|
color: Theme.of(context).hintColor,
|
||||||
|
),
|
||||||
|
const VSpace(8),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 160,
|
width: 160,
|
||||||
child: FlowyButton(
|
child: FlowyButton(
|
||||||
@ -86,6 +94,7 @@ class _EmbedUrlState extends State<_EmbedUrl> {
|
|||||||
return widget.onSubmit(inputText);
|
return widget.onSubmit(inputText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isYouTubeError = youtubeUrlRegex.hasMatch(inputText);
|
||||||
setState(() => isUrlValid = false);
|
setState(() => isUrlValid = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,11 @@ const _videoUrlPattern =
|
|||||||
r'(https?:\/\/)([^\s(["<,>/]*)(\/)[^\s[",><]*(.mp4|.mov|.avi|.webm|.flv|.m4v|.mpeg|.h264)(\?[^\s[",><]*)?';
|
r'(https?:\/\/)([^\s(["<,>/]*)(\/)[^\s[",><]*(.mp4|.mov|.avi|.webm|.flv|.m4v|.mpeg|.h264)(\?[^\s[",><]*)?';
|
||||||
final videoUrlRegex = RegExp(_videoUrlPattern);
|
final videoUrlRegex = RegExp(_videoUrlPattern);
|
||||||
|
|
||||||
|
/// This pattern matches both youtube.com and shortened youtu.be urls.
|
||||||
|
///
|
||||||
|
const _youtubeUrlPattern = r'^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/';
|
||||||
|
final youtubeUrlRegex = RegExp(_youtubeUrlPattern);
|
||||||
|
|
||||||
const _appflowyCloudUrlPattern = r'^(https:\/\/)(.*)(\.appflowy\.cloud\/)(.*)';
|
const _appflowyCloudUrlPattern = r'^(https:\/\/)(.*)(\.appflowy\.cloud\/)(.*)';
|
||||||
final appflowyCloudUrlRegex = RegExp(_appflowyCloudUrlPattern);
|
final appflowyCloudUrlRegex = RegExp(_appflowyCloudUrlPattern);
|
||||||
|
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Simple ChangeNotifier that can be listened to, notifies the
|
||||||
|
/// application on events that should trigger focus loss.
|
||||||
|
///
|
||||||
|
/// Eg. lose focus in AppFlowyEditor
|
||||||
|
///
|
||||||
|
abstract class ShouldLoseFocus with ChangeNotifier {}
|
||||||
|
|
||||||
|
/// Private implementation to allow the [AFFocusManager] to
|
||||||
|
/// call [notifyListeners] without being directly invokable.
|
||||||
|
///
|
||||||
|
class _ShouldLoseFocusImpl extends ShouldLoseFocus {
|
||||||
|
void notify() => notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AFFocusManager extends InheritedWidget {
|
||||||
|
AFFocusManager({super.key, required super.child});
|
||||||
|
|
||||||
|
final ShouldLoseFocus loseFocusNotifier = _ShouldLoseFocusImpl();
|
||||||
|
|
||||||
|
void notifyLoseFocus() {
|
||||||
|
(loseFocusNotifier as _ShouldLoseFocusImpl).notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(covariant InheritedWidget oldWidget) => false;
|
||||||
|
|
||||||
|
static AFFocusManager of(BuildContext context) {
|
||||||
|
final AFFocusManager? result =
|
||||||
|
context.dependOnInheritedWidgetOfExactType<AFFocusManager>();
|
||||||
|
|
||||||
|
assert(result != null, "AFFocusManager could not be found");
|
||||||
|
return result!;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AFFocusManager? maybeOf(BuildContext context) {
|
||||||
|
return context.dependOnInheritedWidgetOfExactType<AFFocusManager>();
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
|||||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||||
|
import 'package:appflowy/workspace/presentation/home/af_focus_manager.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/errors/workspace_failed_screen.dart';
|
import 'package:appflowy/workspace/presentation/home/errors/workspace_failed_screen.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/hotkeys.dart';
|
import 'package:appflowy/workspace/presentation/home/hotkeys.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar.dart';
|
||||||
@ -67,62 +68,68 @@ class DesktopHomeScreen extends StatelessWidget {
|
|||||||
return const WorkspaceFailedScreen();
|
return const WorkspaceFailedScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
return MultiBlocProvider(
|
return AFFocusManager(
|
||||||
key: ValueKey(userProfile.id),
|
child: MultiBlocProvider(
|
||||||
providers: [
|
key: ValueKey(userProfile.id),
|
||||||
BlocProvider<ReminderBloc>.value(value: getIt<ReminderBloc>()),
|
providers: [
|
||||||
BlocProvider<TabsBloc>.value(value: getIt<TabsBloc>()),
|
BlocProvider<ReminderBloc>.value(value: getIt<ReminderBloc>()),
|
||||||
BlocProvider<HomeBloc>(
|
BlocProvider<TabsBloc>.value(value: getIt<TabsBloc>()),
|
||||||
create: (_) =>
|
BlocProvider<HomeBloc>(
|
||||||
HomeBloc(workspaceSetting)..add(const HomeEvent.initial()),
|
create: (_) =>
|
||||||
),
|
HomeBloc(workspaceSetting)..add(const HomeEvent.initial()),
|
||||||
BlocProvider<HomeSettingBloc>(
|
),
|
||||||
create: (_) => HomeSettingBloc(
|
BlocProvider<HomeSettingBloc>(
|
||||||
workspaceSetting,
|
create: (_) => HomeSettingBloc(
|
||||||
context.read<AppearanceSettingsCubit>(),
|
workspaceSetting,
|
||||||
context.widthPx,
|
context.read<AppearanceSettingsCubit>(),
|
||||||
)..add(const HomeSettingEvent.initial()),
|
context.widthPx,
|
||||||
),
|
)..add(const HomeSettingEvent.initial()),
|
||||||
BlocProvider<FavoriteBloc>(
|
),
|
||||||
create: (context) =>
|
BlocProvider<FavoriteBloc>(
|
||||||
FavoriteBloc()..add(const FavoriteEvent.initial()),
|
create: (context) =>
|
||||||
),
|
FavoriteBloc()..add(const FavoriteEvent.initial()),
|
||||||
],
|
),
|
||||||
child: Scaffold(
|
],
|
||||||
floatingActionButton: enableMemoryLeakDetect
|
child: Scaffold(
|
||||||
? const FloatingActionButton(
|
floatingActionButton: enableMemoryLeakDetect
|
||||||
onPressed: dumpMemoryLeak,
|
? const FloatingActionButton(
|
||||||
child: Icon(Icons.memory),
|
onPressed: dumpMemoryLeak,
|
||||||
)
|
child: Icon(Icons.memory),
|
||||||
: null,
|
)
|
||||||
body: BlocListener<HomeBloc, HomeState>(
|
: null,
|
||||||
listenWhen: (p, c) => p.latestView != c.latestView,
|
body: BlocListener<HomeBloc, HomeState>(
|
||||||
listener: (context, state) {
|
listenWhen: (p, c) => p.latestView != c.latestView,
|
||||||
final view = state.latestView;
|
listener: (context, state) {
|
||||||
if (view != null) {
|
final view = state.latestView;
|
||||||
// Only open the last opened view if the [TabsState.currentPageManager] current opened plugin is blank and the last opened view is not null.
|
if (view != null) {
|
||||||
// All opened widgets that display on the home screen are in the form of plugins. There is a list of built-in plugins defined in the [PluginType] enum, including board, grid and trash.
|
// Only open the last opened view if the [TabsState.currentPageManager] current opened plugin is blank and the last opened view is not null.
|
||||||
final currentPageManager =
|
// All opened widgets that display on the home screen are in the form of plugins. There is a list of built-in plugins defined in the [PluginType] enum, including board, grid and trash.
|
||||||
context.read<TabsBloc>().state.currentPageManager;
|
final currentPageManager =
|
||||||
|
context.read<TabsBloc>().state.currentPageManager;
|
||||||
|
|
||||||
if (currentPageManager.plugin.pluginType ==
|
if (currentPageManager.plugin.pluginType ==
|
||||||
PluginType.blank) {
|
PluginType.blank) {
|
||||||
getIt<TabsBloc>().add(
|
getIt<TabsBloc>().add(
|
||||||
TabsEvent.openPlugin(plugin: view.plugin()),
|
TabsEvent.openPlugin(plugin: view.plugin()),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
child: BlocBuilder<HomeSettingBloc, HomeSettingState>(
|
||||||
child: BlocBuilder<HomeSettingBloc, HomeSettingState>(
|
buildWhen: (previous, current) => previous != current,
|
||||||
buildWhen: (previous, current) => previous != current,
|
builder: (context, state) => BlocProvider(
|
||||||
builder: (context, state) => BlocProvider(
|
create: (_) => UserWorkspaceBloc(userProfile: userProfile)
|
||||||
create: (_) => UserWorkspaceBloc(userProfile: userProfile)
|
..add(const UserWorkspaceEvent.initial()),
|
||||||
..add(const UserWorkspaceEvent.initial()),
|
child: HomeHotKeys(
|
||||||
child: HomeHotKeys(
|
userProfile: userProfile,
|
||||||
userProfile: userProfile,
|
child: FlowyContainer(
|
||||||
child: FlowyContainer(
|
Theme.of(context).colorScheme.surface,
|
||||||
Theme.of(context).colorScheme.surface,
|
child: _buildBody(
|
||||||
child: _buildBody(context, userProfile, workspaceSetting),
|
context,
|
||||||
|
userProfile,
|
||||||
|
workspaceSetting,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/startup/tasks/app_window_size_manager.dart';
|
import 'package:appflowy/startup/tasks/app_window_size_manager.dart';
|
||||||
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
|
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
|
||||||
@ -9,7 +11,6 @@ import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
|||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_setting.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_setting.dart';
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
import 'package:hotkey_manager/hotkey_manager.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:scaled_app/scaled_app.dart';
|
import 'package:scaled_app/scaled_app.dart';
|
||||||
@ -54,13 +55,24 @@ class _HomeHotKeysState extends State<HomeHotKeys> {
|
|||||||
final windowSizeManager = WindowSizeManager();
|
final windowSizeManager = WindowSizeManager();
|
||||||
|
|
||||||
late final items = [
|
late final items = [
|
||||||
// Collapse sidebar menu
|
// Collapse sidebar menu (using slash)
|
||||||
HotKeyItem(
|
HotKeyItem(
|
||||||
hotKey: HotKey(
|
hotKey: HotKey(
|
||||||
Platform.isMacOS ? KeyCode.period : KeyCode.backslash,
|
KeyCode.backslash,
|
||||||
modifiers: [Platform.isMacOS ? KeyModifier.meta : KeyModifier.control],
|
modifiers: [Platform.isMacOS ? KeyModifier.meta : KeyModifier.control],
|
||||||
// Set hotkey scope (default is HotKeyScope.system)
|
scope: HotKeyScope.inapp,
|
||||||
scope: HotKeyScope.inapp, // Set as inapp-wide hotkey.
|
),
|
||||||
|
keyDownHandler: (_) => context
|
||||||
|
.read<HomeSettingBloc>()
|
||||||
|
.add(const HomeSettingEvent.collapseMenu()),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Collapse sidebar menu (using .)
|
||||||
|
HotKeyItem(
|
||||||
|
hotKey: HotKey(
|
||||||
|
KeyCode.period,
|
||||||
|
modifiers: [Platform.isMacOS ? KeyModifier.meta : KeyModifier.control],
|
||||||
|
scope: HotKeyScope.inapp,
|
||||||
),
|
),
|
||||||
keyDownHandler: (_) => context
|
keyDownHandler: (_) => context
|
||||||
.read<HomeSettingBloc>()
|
.read<HomeSettingBloc>()
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||||
@ -11,7 +14,6 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
|||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class FavoriteMoreActions extends StatelessWidget {
|
class FavoriteMoreActions extends StatelessWidget {
|
||||||
@ -53,7 +55,7 @@ class FavoriteMoreActions extends StatelessWidget {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ViewMoreActionType.openInNewTab:
|
case ViewMoreActionType.openInNewTab:
|
||||||
context.read<TabsBloc>().openTab(view);
|
getIt<TabsBloc>().openTab(view);
|
||||||
break;
|
break;
|
||||||
case ViewMoreActionType.delete:
|
case ViewMoreActionType.delete:
|
||||||
case ViewMoreActionType.duplicate:
|
case ViewMoreActionType.duplicate:
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
|
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/plugins/document/application/document_appearance_cubit.dart';
|
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||||
|
import 'package:appflowy/workspace/presentation/home/af_focus_manager.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
|
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/hotkeys.dart';
|
import 'package:appflowy/workspace/presentation/home/hotkeys.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
|
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
|
||||||
@ -13,7 +16,6 @@ import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
import 'package:hotkey_manager/hotkey_manager.dart';
|
||||||
|
|
||||||
@ -63,35 +65,37 @@ class UserSettingButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void showSettingsDialog(BuildContext context, UserProfilePB userProfile) =>
|
void showSettingsDialog(BuildContext context, UserProfilePB userProfile) {
|
||||||
showDialog(
|
AFFocusManager.of(context).notifyLoseFocus();
|
||||||
context: context,
|
showDialog(
|
||||||
builder: (dialogContext) => MultiBlocProvider(
|
context: context,
|
||||||
key: _settingsDialogKey,
|
builder: (dialogContext) => MultiBlocProvider(
|
||||||
providers: [
|
key: _settingsDialogKey,
|
||||||
BlocProvider<DocumentAppearanceCubit>.value(
|
providers: [
|
||||||
value: BlocProvider.of<DocumentAppearanceCubit>(dialogContext),
|
BlocProvider<DocumentAppearanceCubit>.value(
|
||||||
),
|
value: BlocProvider.of<DocumentAppearanceCubit>(dialogContext),
|
||||||
BlocProvider.value(value: context.read<UserWorkspaceBloc>()),
|
|
||||||
],
|
|
||||||
child: SettingsDialog(
|
|
||||||
userProfile,
|
|
||||||
didLogout: () async {
|
|
||||||
// Pop the dialog using the dialog context
|
|
||||||
Navigator.of(dialogContext).pop();
|
|
||||||
await runAppFlowy();
|
|
||||||
},
|
|
||||||
dismissDialog: () {
|
|
||||||
if (Navigator.of(dialogContext).canPop()) {
|
|
||||||
return Navigator.of(dialogContext).pop();
|
|
||||||
}
|
|
||||||
Log.warn("Can't pop dialog context");
|
|
||||||
},
|
|
||||||
restartApp: () async {
|
|
||||||
// Pop the dialog using the dialog context
|
|
||||||
Navigator.of(dialogContext).pop();
|
|
||||||
await runAppFlowy();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
|
BlocProvider.value(value: context.read<UserWorkspaceBloc>()),
|
||||||
|
],
|
||||||
|
child: SettingsDialog(
|
||||||
|
userProfile,
|
||||||
|
didLogout: () async {
|
||||||
|
// Pop the dialog using the dialog context
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
await runAppFlowy();
|
||||||
|
},
|
||||||
|
dismissDialog: () {
|
||||||
|
if (Navigator.of(dialogContext).canPop()) {
|
||||||
|
return Navigator.of(dialogContext).pop();
|
||||||
|
}
|
||||||
|
Log.warn("Can't pop dialog context");
|
||||||
|
},
|
||||||
|
restartApp: () async {
|
||||||
|
// Pop the dialog using the dialog context
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
|
await runAppFlowy();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int64_t init_sdk(char *data);
|
int64_t init_sdk(int64_t port, char *data);
|
||||||
|
|
||||||
void async_event(int64_t port, const uint8_t *input, uintptr_t len);
|
void async_event(int64_t port, const uint8_t *input, uintptr_t len);
|
||||||
|
|
||||||
@ -11,6 +11,8 @@ const uint8_t *sync_event(const uint8_t *input, uintptr_t len);
|
|||||||
|
|
||||||
int32_t set_stream_port(int64_t port);
|
int32_t set_stream_port(int64_t port);
|
||||||
|
|
||||||
|
int32_t set_log_stream_port(int64_t port);
|
||||||
|
|
||||||
void link_me_please(void);
|
void link_me_please(void);
|
||||||
|
|
||||||
void rust_log(int64_t level, const char *data);
|
void rust_log(int64_t level, const char *data);
|
||||||
|
@ -442,7 +442,7 @@
|
|||||||
"manageDataPage": {
|
"manageDataPage": {
|
||||||
"menuLabel": "Manage data",
|
"menuLabel": "Manage data",
|
||||||
"title": "Manage data",
|
"title": "Manage data",
|
||||||
"description": "Manage data local storage or Import your existing data into @:appName. You can secure your data with end to end encryption.",
|
"description": "Manage data local storage or Import your existing data into @:appName.",
|
||||||
"dataStorage": {
|
"dataStorage": {
|
||||||
"title": "File storage location",
|
"title": "File storage location",
|
||||||
"tooltip": "The location where your files are stored",
|
"tooltip": "The location where your files are stored",
|
||||||
@ -550,7 +550,7 @@
|
|||||||
},
|
},
|
||||||
"showNotificationsIcon": {
|
"showNotificationsIcon": {
|
||||||
"label": "Show notifications icon",
|
"label": "Show notifications icon",
|
||||||
"hint": "Turn off to hide notification icons in the app."
|
"hint": "Toggle off to hide the notification icon in the sidebar."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"appearance": {
|
"appearance": {
|
||||||
@ -1143,10 +1143,11 @@
|
|||||||
"video": {
|
"video": {
|
||||||
"label": "Video",
|
"label": "Video",
|
||||||
"emptyLabel": "Add a video",
|
"emptyLabel": "Add a video",
|
||||||
"placeholder": "Enter a link to a video",
|
"placeholder": "Paste the video link",
|
||||||
"copiedToPasteBoard": "The video link has been copied to the clipboard",
|
"copiedToPasteBoard": "The video link has been copied to the clipboard",
|
||||||
"insertVideo": "Insert video",
|
"insertVideo": "Add video",
|
||||||
"invalidVideoUrl": "Invalid video url, must be a valid file.",
|
"invalidVideoUrl": "The source URL is not supported yet.",
|
||||||
|
"invalidVideoUrlYouTube": "YouTube is not supported yet.",
|
||||||
"supportedFormats": "Supported formats: MP4, WebM, MOV, AVI, FLV, MPEG/M4V, H.264"
|
"supportedFormats": "Supported formats: MP4, WebM, MOV, AVI, FLV, MPEG/M4V, H.264"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -59,6 +59,7 @@ AppDir:
|
|||||||
- libwayland-cursor0:amd64
|
- libwayland-cursor0:amd64
|
||||||
- libwayland-client0:amd64
|
- libwayland-client0:amd64
|
||||||
- libwayland-egl1:amd64
|
- libwayland-egl1:amd64
|
||||||
|
- libmpv-dev:amd64
|
||||||
- mpv:amd64
|
- mpv:amd64
|
||||||
files:
|
files:
|
||||||
include: []
|
include: []
|
||||||
|
Loading…
Reference in New Issue
Block a user