fix: launch review 0.5.8 (#5367)

This commit is contained in:
Mathias Mogensen 2024-05-21 11:34:36 +02:00 committed by GitHub
parent b7bc847107
commit b2978e0d6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 365 additions and 145 deletions

View File

@ -0,0 +1,32 @@
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('MoreViewActions', () {
testWidgets('can duplicate and delete from menu', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.pumpAndSettle();
final pageFinder = find.byType(ViewItem);
expect(pageFinder, findsNWidgets(1));
// Duplicate
await tester.openMoreViewActions();
await tester.duplicateByMoreViewActions();
expect(pageFinder, findsNWidgets(2));
// Delete
await tester.openMoreViewActions();
await tester.deleteByMoreViewActions();
expect(pageFinder, findsNWidgets(1));
});
});
}

View File

@ -6,6 +6,9 @@ import 'document_copy_and_paste_test.dart' as document_copy_and_paste_test;
import 'document_create_and_delete_test.dart'
as document_create_and_delete_test;
import 'document_option_action_test.dart' as document_option_action_test;
import 'document_inline_page_reference_test.dart'
as document_inline_page_reference_test;
import 'document_more_actions_test.dart' as document_more_actions_test;
import 'document_text_direction_test.dart' as document_text_direction_test;
import 'document_with_cover_image_test.dart' as document_with_cover_image_test;
import 'document_with_database_test.dart' as document_with_database_test;
@ -16,8 +19,6 @@ import 'document_with_inline_page_test.dart' as document_with_inline_page_test;
import 'document_with_outline_block_test.dart' as document_with_outline_block;
import 'document_with_toggle_list_test.dart' as document_with_toggle_list_test;
import 'edit_document_test.dart' as document_edit_test;
import 'document_inline_page_reference_test.dart'
as document_inline_page_reference_test;
void startTesting() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@ -38,4 +39,5 @@ void startTesting() {
document_option_action_test.main();
document_with_image_block_test.main();
document_inline_page_reference_test.main();
document_more_actions_test.main();
}

View File

@ -1,5 +1,10 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
@ -22,15 +27,13 @@ import 'package:appflowy/workspace/presentation/notifications/widgets/flowy_tab.
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_button.dart';
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_tab_bar.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
import 'package:appflowy/workspace/presentation/widgets/more_view_actions/more_view_actions.dart';
import 'package:appflowy/workspace/presentation/widgets/more_view_actions/widgets/common_view_action.dart';
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'emoji.dart';
@ -564,6 +567,44 @@ extension CommonOperations on WidgetTester {
);
await tapButton(button);
}
Future<void> openMoreViewActions() async {
final button = find.byType(MoreViewActions);
await tap(button);
await pumpAndSettle();
}
/// Presses on the Duplicate ViewAction in the [MoreViewActions] popup.
///
/// [openMoreViewActions] must be called beforehand!
///
Future<void> duplicateByMoreViewActions() async {
final button = find.descendant(
of: find.byType(ListView),
matching: find.byWidgetPredicate(
(widget) =>
widget is ViewAction && widget.type == ViewActionType.duplicate,
),
);
await tap(button);
await pump();
}
/// Presses on the Delete ViewAction in the [MoreViewActions] popup.
///
/// [openMoreViewActions] must be called beforehand!
///
Future<void> deleteByMoreViewActions() async {
final button = find.descendant(
of: find.byType(ListView),
matching: find.byWidgetPredicate(
(widget) =>
widget is ViewAction && widget.type == ViewActionType.delete,
),
);
await tap(button);
await pump();
}
}
extension SettingsFinder on CommonFinders {

View File

@ -29,9 +29,7 @@ class FontPickerScreen extends StatelessWidget {
}
class LanguagePickerPage extends StatefulWidget {
const LanguagePickerPage({
super.key,
});
const LanguagePickerPage({super.key});
@override
State<LanguagePickerPage> createState() => _LanguagePickerPageState();
@ -43,7 +41,6 @@ class _LanguagePickerPageState extends State<LanguagePickerPage> {
@override
void initState() {
super.initState();
availableFonts = _availableFonts;
}
@ -90,7 +87,6 @@ class _FontSelectorState extends State<FontSelector> {
@override
void initState() {
super.initState();
availableFonts = _availableFonts;
}

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:appflowy/plugins/base/emoji/emoji_picker_header.dart';
import 'package:appflowy/plugins/base/emoji/emoji_search_bar.dart';
import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_emoji_mart/flutter_emoji_mart.dart';
@ -83,7 +84,9 @@ class _FlowyEmojiPickerState extends State<FlowyEmojiPicker> {
},
itemBuilder: (context, emojiId, emoji, callback) {
return FlowyIconButton(
iconPadding: const EdgeInsets.all(2.0),
iconPadding: PlatformExtension.isWindows
? const EdgeInsets.only(bottom: 2.0)
: const EdgeInsets.all(2),
icon: FlowyText(
emoji,
fontSize: 28.0,

View File

@ -113,7 +113,7 @@ typedef WorkspaceSettingNotifyValue
class UserWorkspaceListener {
UserWorkspaceListener();
PublishNotifier<WorkspaceSettingNotifyValue>? _settingChangedNotifier =
final PublishNotifier<WorkspaceSettingNotifyValue> _settingChangedNotifier =
PublishNotifier();
FolderNotificationListener? _listener;
@ -122,7 +122,7 @@ class UserWorkspaceListener {
void Function(WorkspaceSettingNotifyValue)? onSettingUpdated,
}) {
if (onSettingUpdated != null) {
_settingChangedNotifier?.addPublishListener(onSettingUpdated);
_settingChangedNotifier.addPublishListener(onSettingUpdated);
}
// The "current-workspace" is predefined in the backend. Do not try to
@ -140,13 +140,11 @@ class UserWorkspaceListener {
switch (ty) {
case FolderNotification.DidUpdateWorkspaceSetting:
result.fold(
(payload) => _settingChangedNotifier?.value =
(payload) => _settingChangedNotifier.value =
FlowyResult.success(WorkspaceSettingPB.fromBuffer(payload)),
(error) =>
_settingChangedNotifier?.value = FlowyResult.failure(error),
(error) => _settingChangedNotifier.value = FlowyResult.failure(error),
);
break;
default:
break;
}
@ -154,8 +152,6 @@ class UserWorkspaceListener {
Future<void> stop() async {
await _listener?.stop();
_settingChangedNotifier?.dispose();
_settingChangedNotifier = null;
_settingChangedNotifier.dispose();
}
}

View File

@ -0,0 +1,5 @@
import 'package:flutter/material.dart';
extension IsLightMode on ThemeData {
bool get isLightMode => brightness == Brightness.light;
}

View File

@ -8,6 +8,6 @@ extension TimeFormatter on UserTimeFormatPB {
}
final _toFormat = {
UserTimeFormatPB.TwelveHour: DateFormat.Hm(),
UserTimeFormatPB.TwentyFourHour: DateFormat.jm(),
UserTimeFormatPB.TwentyFourHour: DateFormat.Hm(),
UserTimeFormatPB.TwelveHour: DateFormat.jm(),
};

View File

@ -56,7 +56,13 @@ class WorkspaceSettingsBloc
?.role ??
AFRolePB.Guest;
emit(state.copyWith(members: members, myRole: role));
emit(
state.copyWith(
workspace: currentWorkspaceInList,
members: members,
myRole: role,
),
);
} catch (e) {
Log.error('Failed to get or create current workspace');
}

View File

@ -38,6 +38,7 @@ class _WorkspaceIconState extends State<WorkspaceIcon> {
child: EmojiText(
emoji: widget.workspace.icon,
fontSize: widget.iconSize,
lineHeight: 1,
),
)
: Container(

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
@ -78,46 +79,46 @@ class _SettingsAccountViewState extends State<SettingsAccountView> {
],
),
// Enable when/if we need change email feature
// // Only show change email if the user is authenticated and not using local auth
// if (isAuthEnabled &&
// state.userProfile.authenticator != AuthenticatorPB.Local) ...[
// const SettingsCategorySpacer(),
// SettingsCategory(
// title: LocaleKeys.settings_accountPage_email_title.tr(),
// children: [
// SingleSettingAction(
// label: state.userProfile.email,
// buttonLabel: LocaleKeys
// .settings_accountPage_email_actions_change
// .tr(),
// onPressed: () => SettingsAlertDialog(
// title: LocaleKeys
// .settings_accountPage_email_actions_change
// .tr(),
// confirmLabel: LocaleKeys.button_save.tr(),
// confirm: () {
// context.read<SettingsUserViewBloc>().add(
// SettingsUserEvent.updateUserEmail(
// _emailController.text,
// ),
// );
// Navigator.of(context).pop();
// },
// children: [
// SettingsInputField(
// label: LocaleKeys.settings_accountPage_email_title
// .tr(),
// value: state.userProfile.email,
// hideActions: true,
// textController: _emailController,
// ),
// ],
// ).show(context),
// ),
// ],
// ),
// ],
// Only show email if the user is authenticated and not using local auth
if (isAuthEnabled &&
state.userProfile.authenticator != AuthenticatorPB.Local) ...[
SettingsCategory(
title: LocaleKeys.settings_accountPage_email_title.tr(),
children: [
FlowyText.regular(state.userProfile.email),
// Enable when/if we need change email feature
// SingleSettingAction(
// label: state.userProfile.email,
// buttonLabel: LocaleKeys
// .settings_accountPage_email_actions_change
// .tr(),
// onPressed: () => SettingsAlertDialog(
// title: LocaleKeys
// .settings_accountPage_email_actions_change
// .tr(),
// confirmLabel: LocaleKeys.button_save.tr(),
// confirm: () {
// context.read<SettingsUserViewBloc>().add(
// SettingsUserEvent.updateUserEmail(
// _emailController.text,
// ),
// );
// Navigator.of(context).pop();
// },
// children: [
// SettingsInputField(
// label: LocaleKeys.settings_accountPage_email_title
// .tr(),
// value: state.userProfile.email,
// hideActions: true,
// textController: _emailController,
// ),
// ],
// ).show(context),
// ),
],
),
],
/// Enable when we have change password feature and 2FA
// const SettingsCategorySpacer(),

View File

@ -9,6 +9,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/appflowy_cache_manager.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/startup/tasks/rust_sdk.dart';
import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/settings/setting_file_importer_bloc.dart';
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
@ -55,6 +56,9 @@ class SettingsManageDataView extends StatelessWidget {
actions: [
if (state.mapOrNull(didReceivedPath: (_) => true) == true)
SettingAction(
tooltip: LocaleKeys
.settings_manageDataPage_dataStorage_actions_resetTooltip
.tr(),
icon: const FlowySvg(FlowySvgs.restore_s),
label: LocaleKeys.settings_common_reset.tr(),
onPressed: () => SettingsAlertDialog(
@ -375,6 +379,8 @@ class _CurrentPathState extends State<_CurrentPath> {
@override
Widget build(BuildContext context) {
final isLM = Theme.of(context).isLightMode;
return Column(
children: [
Row(
@ -392,7 +398,9 @@ class _CurrentPathState extends State<_CurrentPath> {
maxLines: 2,
overflow: TextOverflow.ellipsis,
decoration: isHovering ? TextDecoration.underline : null,
color: const Color(0xFF005483),
color: isLM
? const Color(0xFF005483)
: Theme.of(context).colorScheme.primary,
),
),
),

View File

@ -1,4 +1,5 @@
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';
@ -18,12 +19,12 @@ import 'package:appflowy/workspace/presentation/settings/shared/af_dropdown_menu
import 'package:appflowy/workspace/presentation/settings/shared/document_color_setting_button.dart';
import 'package:appflowy/workspace/presentation/settings/shared/setting_action.dart';
import 'package:appflowy/workspace/presentation/settings/shared/setting_list_tile.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_actionable_input.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_alert_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_category.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_dashed_divider.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_dropdown.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_input_field.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_radio_select.dart';
import 'package:appflowy/workspace/presentation/settings/shared/single_setting_action.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload_view.dart';
@ -41,39 +42,22 @@ import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
class SettingsWorkspaceView extends StatefulWidget {
class SettingsWorkspaceView extends StatelessWidget {
const SettingsWorkspaceView({super.key, required this.userProfile});
final UserProfilePB userProfile;
@override
State<SettingsWorkspaceView> createState() => _SettingsWorkspaceViewState();
}
class _SettingsWorkspaceViewState extends State<SettingsWorkspaceView> {
final TextEditingController _workspaceNameController =
TextEditingController();
@override
void dispose() {
_workspaceNameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider<WorkspaceSettingsBloc>(
create: (context) => WorkspaceSettingsBloc()
..add(WorkspaceSettingsEvent.initial(userProfile: widget.userProfile)),
..add(WorkspaceSettingsEvent.initial(userProfile: userProfile)),
child: BlocConsumer<WorkspaceSettingsBloc, WorkspaceSettingsState>(
listener: (context, state) {
if ((state.workspace?.name ?? '') != _workspaceNameController.text) {
_workspaceNameController.text = state.workspace?.name ?? '';
}
if (state.deleteWorkspace) {
context.read<UserWorkspaceBloc>().add(
UserWorkspaceEvent.deleteWorkspace(
@ -97,44 +81,11 @@ class _SettingsWorkspaceViewState extends State<SettingsWorkspaceView> {
description: LocaleKeys.settings_workspacePage_description.tr(),
children: [
// We don't allow changing workspace name/icon for local/offline
if (state.workspace != null &&
widget.userProfile.authenticator !=
AuthenticatorPB.Local) ...[
if (userProfile.authenticator != AuthenticatorPB.Local) ...[
SettingsCategory(
title: LocaleKeys.settings_workspacePage_workspaceName_title
.tr(),
children: [
SettingsActionableInput(
controller: _workspaceNameController,
onSave: (value) => _saveWorkspaceName(
context,
current: state.workspace!.name,
name: value,
),
actions: [
SizedBox(
height: 48,
child: FlowyTextButton(
LocaleKeys.button_save.tr(),
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
fontWeight: FontWeight.w600,
radius: BorderRadius.circular(12),
fillColor: Theme.of(context).colorScheme.primary,
hoverColor: const Color(0xFF005483),
fontHoverColor: Colors.white,
onPressed: () => _saveWorkspaceName(
context,
current: state.workspace!.name,
name: _workspaceNameController.text,
),
),
),
],
),
],
children: const [_WorkspaceNameSetting()],
),
SettingsCategory(
title: LocaleKeys.settings_workspacePage_workspaceIcon_title
@ -143,7 +94,10 @@ class _SettingsWorkspaceViewState extends State<SettingsWorkspaceView> {
.settings_workspacePage_workspaceIcon_description
.tr(),
children: [
_WorkspaceIconSetting(workspace: state.workspace!),
_WorkspaceIconSetting(
enableEdit: state.myRole.isOwner,
workspace: state.workspace,
),
],
),
],
@ -195,9 +149,7 @@ class _SettingsWorkspaceViewState extends State<SettingsWorkspaceView> {
title: LocaleKeys.settings_workspacePage_language_title.tr(),
children: const [LanguageDropdown()],
),
if (state.workspace != null &&
widget.userProfile.authenticator !=
AuthenticatorPB.Local) ...[
if (userProfile.authenticator != AuthenticatorPB.Local) ...[
SingleSettingAction(
label: LocaleKeys.settings_workspacePage_manageWorkspace_title
.tr(),
@ -244,17 +196,115 @@ class _SettingsWorkspaceViewState extends State<SettingsWorkspaceView> {
),
);
}
}
void _saveWorkspaceName(
BuildContext context, {
required String current,
class _WorkspaceNameSetting extends StatefulWidget {
const _WorkspaceNameSetting();
@override
State<_WorkspaceNameSetting> createState() => _WorkspaceNameSettingState();
}
class _WorkspaceNameSettingState extends State<_WorkspaceNameSetting> {
final TextEditingController workspaceNameController = TextEditingController();
late final FocusNode focusNode;
bool isEditing = false;
@override
void initState() {
super.initState();
focusNode = FocusNode(
onKeyEvent: (_, event) {
if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.escape &&
isEditing &&
mounted) {
setState(() => isEditing = false);
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
},
)..addListener(() {
if (!focusNode.hasFocus && isEditing && mounted) {
_saveWorkspaceName(name: workspaceNameController.text);
setState(() => isEditing = false);
}
});
}
@override
void dispose() {
focusNode.dispose();
workspaceNameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocConsumer<WorkspaceSettingsBloc, WorkspaceSettingsState>(
listener: (_, state) {
final newName = state.workspace?.name;
if (newName != null && newName != workspaceNameController.text) {
workspaceNameController.text = newName;
}
},
builder: (_, state) {
if (isEditing) {
return Flexible(
child: SettingsInputField(
textController: workspaceNameController,
value: workspaceNameController.text,
focusNode: focusNode..requestFocus(),
onCancel: () => setState(() => isEditing = false),
onSave: (_) {
_saveWorkspaceName(name: workspaceNameController.text);
setState(() => isEditing = false);
},
),
);
}
return Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 2.5),
child: FlowyText.regular(
workspaceNameController.text,
fontSize: 14,
),
),
if (state.myRole.isOwner) ...[
const HSpace(4),
FlowyTooltip(
message: LocaleKeys
.settings_workspacePage_workspaceName_editTooltip
.tr(),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => isEditing = true),
child: const FlowyHover(
resetHoverOnRebuild: false,
child: Padding(
padding: EdgeInsets.all(4),
child: FlowySvg(FlowySvgs.edit_s),
),
),
),
),
],
],
);
},
);
}
void _saveWorkspaceName({
required String name,
}) {
if (name.isNotEmpty && name != current) {
if (name.isNotEmpty) {
context.read<WorkspaceSettingsBloc>().add(
WorkspaceSettingsEvent.updateWorkspaceName(
_workspaceNameController.text,
),
WorkspaceSettingsEvent.updateWorkspaceName(name),
);
if (context.mounted) {
@ -300,12 +350,21 @@ class LanguageDropdown extends StatelessWidget {
}
class _WorkspaceIconSetting extends StatelessWidget {
const _WorkspaceIconSetting({required this.workspace});
const _WorkspaceIconSetting({required this.enableEdit, this.workspace});
final UserWorkspacePB workspace;
final bool enableEdit;
final UserWorkspacePB? workspace;
@override
Widget build(BuildContext context) {
if (workspace == null) {
return const SizedBox(
height: 64,
width: 64,
child: CircularProgressIndicator(),
);
}
return Container(
height: 64,
width: 64,
@ -316,9 +375,9 @@ class _WorkspaceIconSetting extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.all(1),
child: WorkspaceIcon(
workspace: workspace,
iconSize: workspace.icon.isNotEmpty == true ? 46 : 20,
enableEdit: true,
workspace: workspace!,
iconSize: workspace!.icon.isNotEmpty == true ? 46 : 20,
enableEdit: enableEdit,
onSelected: (r) => context
.read<WorkspaceSettingsBloc>()
.add(WorkspaceSettingsEvent.updateWorkspaceIcon(r.emoji)),
@ -508,6 +567,7 @@ class _DateTimeFormatLabel extends StatelessWidget {
now.timeZoneName,
],
),
maxLines: 2,
fontSize: 16,
color: AFThemeExtension.of(context).secondaryTextColor,
);
@ -712,6 +772,9 @@ class AppearanceSelector extends StatelessWidget {
),
),
),
child: t != themeMode
? null
: const _SelectedModeIndicator(),
),
const VSpace(6),
FlowyText.regular(getLabel(t), textAlign: TextAlign.center),
@ -735,6 +798,38 @@ class AppearanceSelector extends StatelessWidget {
};
}
class _SelectedModeIndicator extends StatelessWidget {
const _SelectedModeIndicator();
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned(
top: 4,
left: 4,
child: Material(
shape: const CircleBorder(),
elevation: 2,
child: Container(
decoration: const BoxDecoration(
shape: BoxShape.circle,
),
height: 16,
width: 16,
child: const FlowySvg(
FlowySvgs.settings_selected_theme_m,
size: Size.square(16),
blendMode: BlendMode.dstIn,
),
),
),
),
],
);
}
}
class _FontSelectorDropdown extends StatelessWidget {
const _FontSelectorDropdown();
@ -777,6 +872,7 @@ class _FontSelectorDropdown extends StatelessWidget {
selectedValue: appearance.font,
value: font,
label: font.fontFamilyDisplayName,
fontFamily: font,
),
)
.toList(),

View File

@ -1,3 +1,5 @@
import 'package:appflowy/shared/google_fonts_extension.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
@ -10,7 +12,12 @@ DropdownMenuEntry<T> buildDropdownMenuEntry<T>(
T? selectedValue,
Widget? leadingWidget,
Widget? trailingWidget,
String? fontFamily,
}) {
final fontFamilyUsed = fontFamily != null
? getGoogleFontSafely(fontFamily).fontFamily ?? defaultFontFamily
: defaultFontFamily;
return DropdownMenuEntry<T>(
style: ButtonStyle(
foregroundColor:
@ -26,7 +33,12 @@ DropdownMenuEntry<T> buildDropdownMenuEntry<T>(
leadingIcon: leadingWidget,
labelWidget: Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: FlowyText.medium(label, fontSize: 14, textAlign: TextAlign.start),
child: FlowyText.medium(
label,
fontSize: 14,
textAlign: TextAlign.start,
fontFamily: fontFamilyUsed,
),
),
trailingIcon: Row(
children: [

View File

@ -1,9 +1,13 @@
import 'package:appflowy/shared/google_fonts_extension.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/flutter/af_dropdown_menu.dart';
import 'package:collection/collection.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SettingsDropdown<T> extends StatefulWidget {
const SettingsDropdown({
@ -37,6 +41,10 @@ class _SettingsDropdownState<T> extends State<SettingsDropdown<T>> {
@override
Widget build(BuildContext context) {
final fontFamily = context.read<AppearanceSettingsCubit>().state.font;
final fontFamilyUsed =
getGoogleFontSafely(fontFamily).fontFamily ?? defaultFontFamily;
return Row(
children: [
Expanded(
@ -45,6 +53,10 @@ class _SettingsDropdownState<T> extends State<SettingsDropdown<T>> {
expandedInsets: widget.expandWidth ? EdgeInsets.zero : null,
initialSelection: widget.selectedOption,
dropdownMenuEntries: widget.options,
textStyle: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(fontFamily: fontFamilyUsed),
menuStyle: MenuStyle(
maximumSize:
const MaterialStatePropertyAll(Size(double.infinity, 250)),

View File

@ -5,7 +5,6 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/af_role_pb_extension.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_category_spacer.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/members/workspace_member_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
@ -37,8 +36,6 @@ class WorkspaceMembersPage extends StatelessWidget {
title: LocaleKeys.settings_appearance_members_title.tr(),
children: [
if (state.myRole.canInvite) const _InviteMember(),
if (state.myRole.canInvite && state.members.isNotEmpty)
const SettingsCategorySpacer(),
if (state.members.isNotEmpty)
_MemberList(
members: state.members,

View File

@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#14AE5C"/>
<circle cx="12" cy="12" r="9" fill="white"/>
<mask id="mask0_3623_112333" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<rect width="24" height="24" fill="#66CF80"/>
</mask>
<g mask="url(#mask0_3623_112333)">
<path d="M10.598 16.6L17.648 9.55L16.248 8.15L10.598 13.8L7.74805 10.95L6.34805 12.35L10.598 16.6ZM11.998 22C10.6147 22 9.31471 21.7375 8.09805 21.2125C6.88138 20.6875 5.82305 19.975 4.92305 19.075C4.02305 18.175 3.31055 17.1167 2.78555 15.9C2.26055 14.6833 1.99805 13.3833 1.99805 12C1.99805 10.6167 2.26055 9.31667 2.78555 8.1C3.31055 6.88333 4.02305 5.825 4.92305 4.925C5.82305 4.025 6.88138 3.3125 8.09805 2.7875C9.31471 2.2625 10.6147 2 11.998 2C13.3814 2 14.6814 2.2625 15.898 2.7875C17.1147 3.3125 18.173 4.025 19.073 4.925C19.973 5.825 20.6855 6.88333 21.2105 8.1C21.7355 9.31667 21.998 10.6167 21.998 12C21.998 13.3833 21.7355 14.6833 21.2105 15.9C20.6855 17.1167 19.973 18.175 19.073 19.075C18.173 19.975 17.1147 20.6875 15.898 21.2125C14.6814 21.7375 13.3814 22 11.998 22Z" fill="#66CF80"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -353,7 +353,8 @@
"description": "Customize your workspace appearance, theme, font, text layout, date-/time-format, and language.",
"workspaceName": {
"title": "Workspace name",
"savedMessage": "Saved workspace name"
"savedMessage": "Saved workspace name",
"editTooltip": "Edit workspace name"
},
"workspaceIcon": {
"title": "Workspace icon",
@ -429,7 +430,8 @@
"open": "Open folder",
"openTooltip": "Open current data folder location",
"copy": "Copy path",
"copiedHint": "Link copied!"
"copiedHint": "Path copied!",
"resetTooltip": "Reset to default location"
},
"resetDialog": {
"title": "Are you sure?",
@ -1673,4 +1675,4 @@
"betaTooltip": "We currently only support searching for pages",
"fromTrashHint": "From trash"
}
}
}

View File

@ -12,7 +12,7 @@ pub enum FolderNotification {
Unknown = 0,
/// Trigger after creating a workspace
DidCreateWorkspace = 1,
// /// Trigger after updating a workspace
/// Trigger after updating a workspace
DidUpdateWorkspace = 2,
DidUpdateWorkspaceViews = 3,