fix: launch review improvements (#5263)

* fix: recent views fix

* fix: text button font color

* fix: sidebar scrollbar inset

* fix: account settings launch review

* fix: open + menu on mobile provider issue

* fix: code review

* fix: push view improvement
This commit is contained in:
Mathias Mogensen 2024-05-06 12:13:17 +02:00 committed by GitHub
parent 3bdc8c222c
commit c4f6703b76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 271 additions and 365 deletions

View File

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:appflowy/mobile/presentation/database/board/mobile_board_screen.dart'; import 'package:appflowy/mobile/presentation/database/board/mobile_board_screen.dart';
@ -19,6 +20,7 @@ extension MobileRouter on BuildContext {
queryParameters: view.queryParameters(arguments), queryParameters: view.queryParameters(arguments),
).toString(), ).toString(),
).then((value) { ).then((value) {
getIt<MenuSharedState>().latestOpenView = view;
getIt<CachedRecentService>().updateRecentViews([view.id], true); getIt<CachedRecentService>().updateRecentViews([view.id], true);
}); });
} }

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart'; import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/home/favorite_folder/mobile_home_favorite_folder.dart'; import 'package:appflowy/mobile/presentation/home/favorite_folder/mobile_home_favorite_folder.dart';
@ -8,7 +10,6 @@ import 'package:appflowy/workspace/application/user/user_workspace_bloc.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: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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_slidable/flutter_slidable.dart';
@ -28,23 +29,15 @@ class MobileFavoritePageFolder extends StatelessWidget {
providers: [ providers: [
BlocProvider( BlocProvider(
create: (_) => SidebarSectionsBloc() create: (_) => SidebarSectionsBloc()
..add( ..add(SidebarSectionsEvent.initial(userProfile, workspaceId)),
SidebarSectionsEvent.initial(
userProfile,
workspaceId,
),
),
), ),
BlocProvider( BlocProvider(
create: (_) => FavoriteBloc()..add(const FavoriteEvent.initial()), create: (_) => FavoriteBloc()..add(const FavoriteEvent.initial()),
), ),
], ],
child: BlocListener<UserWorkspaceBloc, UserWorkspaceState>( child: BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
listener: (context, state) { listener: (context, state) =>
context.read<FavoriteBloc>().add( context.read<FavoriteBloc>().add(const FavoriteEvent.initial()),
const FavoriteEvent.initial(),
);
},
child: MultiBlocListener( child: MultiBlocListener(
listeners: [ listeners: [
BlocListener<SidebarSectionsBloc, SidebarSectionsState>( BlocListener<SidebarSectionsBloc, SidebarSectionsState>(

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/mobile/application/mobile_router.dart'; import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart';
import 'package:appflowy/mobile/presentation/home/favorite_folder/mobile_home_favorite_folder_header.dart'; import 'package:appflowy/mobile/presentation/home/favorite_folder/mobile_home_favorite_folder_header.dart';
@ -5,7 +7,6 @@ import 'package:appflowy/mobile/presentation/page_item/mobile_view_item.dart';
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart'; import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class MobileFavoriteFolder extends StatelessWidget { class MobileFavoriteFolder extends StatelessWidget {
@ -62,9 +63,7 @@ class MobileFavoriteFolder extends StatelessWidget {
isFeedback: false, isFeedback: false,
view: view, view: view,
level: 0, level: 0,
onSelected: (view) async { onSelected: context.pushView,
await context.pushView(view);
},
endActionPane: (context) => buildEndActionPane(context, [ endActionPane: (context) => buildEndActionPane(context, [
view.isFavorite view.isFavorite
? MobilePaneActionType.removeFromFavorites ? MobilePaneActionType.removeFromFavorites

View File

@ -24,16 +24,16 @@ class _MobileRecentFolderState extends State<MobileRecentFolder> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => RecentViewsBloc() create: (context) =>
..add( RecentViewsBloc()..add(const RecentViewsEvent.initial()),
const RecentViewsEvent.initial(),
),
child: BlocListener<UserWorkspaceBloc, UserWorkspaceState>( child: BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
listener: (context, state) { listenWhen: (previous, current) =>
context.read<RecentViewsBloc>().add( current.currentWorkspace != null &&
const RecentViewsEvent.fetchRecentViews(), previous.currentWorkspace?.workspaceId !=
); current.currentWorkspace!.workspaceId,
}, listener: (context, state) => context
.read<RecentViewsBloc>()
.add(const RecentViewsEvent.resetRecentViews()),
child: BlocBuilder<RecentViewsBloc, RecentViewsState>( child: BlocBuilder<RecentViewsBloc, RecentViewsState>(
builder: (context, state) { builder: (context, state) {
final ids = <String>{}; final ids = <String>{};

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart'; import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/default_mobile_action_pane.dart';
@ -9,7 +11,6 @@ import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class MobileSectionFolder extends StatelessWidget { class MobileSectionFolder extends StatelessWidget {
@ -71,9 +72,7 @@ class MobileSectionFolder extends StatelessWidget {
level: 0, level: 0,
leftPadding: 16, leftPadding: 16,
isFeedback: false, isFeedback: false,
onSelected: (view) async { onSelected: context.pushView,
await context.pushView(view);
},
endActionPane: (context) { endActionPane: (context) {
final view = context.read<ViewBloc>().state.view; final view = context.read<ViewBloc>().state.view;
return buildEndActionPane(context, [ return buildEndActionPane(context, [

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart'; import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
@ -10,7 +12,6 @@ import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_it
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_slidable/flutter_slidable.dart';

View File

@ -11,10 +11,7 @@ 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';
class SettingButton extends StatefulWidget { class SettingButton extends StatefulWidget {
const SettingButton({ const SettingButton({super.key, required this.databaseController});
super.key,
required this.databaseController,
});
final DatabaseController databaseController; final DatabaseController databaseController;
@ -44,9 +41,8 @@ class _SettingButtonState extends State<SettingButton> {
radius: Corners.s4Border, radius: Corners.s4Border,
onPressed: _popoverController.show, onPressed: _popoverController.show,
), ),
popupBuilder: (BuildContext context) => DatabaseSettingsList( popupBuilder: (_) =>
databaseController: widget.databaseController, DatabaseSettingsList(databaseController: widget.databaseController),
),
); );
} }
} }

View File

@ -325,24 +325,20 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
final editorState = widget.editorState; final editorState = widget.editorState;
if (PlatformExtension.isMobile) { if (PlatformExtension.isMobile) {
return BlocProvider.value( return AppFlowyMobileToolbar(
value: documentBloc, toolbarHeight: 42.0,
child: AppFlowyMobileToolbar( editorState: editorState,
toolbarHeight: 42.0, toolbarItemsBuilder: (sel) => buildMobileToolbarItems(editorState, sel),
child: MobileFloatingToolbar(
editorState: editorState, editorState: editorState,
toolbarItemsBuilder: (selection) => editorScrollController: editorScrollController,
buildMobileToolbarItems(editorState, selection), toolbarBuilder: (_, anchor, closeToolbar) =>
child: MobileFloatingToolbar( CustomMobileFloatingToolbar(
editorState: editorState, editorState: editorState,
editorScrollController: editorScrollController, anchor: anchor,
toolbarBuilder: (_, anchor, closeToolbar) => closeToolbar: closeToolbar,
CustomMobileFloatingToolbar(
editorState: editorState,
anchor: anchor,
closeToolbar: closeToolbar,
),
child: editor,
), ),
child: editor,
), ),
); );
} }

View File

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart'; import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
import 'package:appflowy/plugins/base/icon/icon_picker.dart'; import 'package:appflowy/plugins/base/icon/icon_picker.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_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.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:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
class EmojiPickerButton extends StatelessWidget { class EmojiPickerButton extends StatelessWidget {
@ -41,7 +42,7 @@ class EmojiPickerButton extends StatelessWidget {
), ),
offset: offset, offset: offset,
direction: direction ?? PopoverDirection.rightWithTopAligned, direction: direction ?? PopoverDirection.rightWithTopAligned,
popupBuilder: (context) => Container( popupBuilder: (_) => Container(
width: emojiPickerSize.width, width: emojiPickerSize.width,
height: emojiPickerSize.height, height: emojiPickerSize.height,
padding: const EdgeInsets.all(4.0), padding: const EdgeInsets.all(4.0),
@ -54,7 +55,7 @@ class EmojiPickerButton extends StatelessWidget {
? FlowyButton( ? FlowyButton(
useIntrinsicWidth: true, useIntrinsicWidth: true,
text: defaultIcon!, text: defaultIcon!,
onTap: () => popoverController.show(), onTap: popoverController.show,
) )
: FlowyTextButton( : FlowyTextButton(
emoji, emoji,
@ -64,37 +65,29 @@ class EmojiPickerButton extends StatelessWidget {
constraints: const BoxConstraints(minWidth: 35.0), constraints: const BoxConstraints(minWidth: 35.0),
fillColor: Colors.transparent, fillColor: Colors.transparent,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
onPressed: () { onPressed: popoverController.show,
popoverController.show();
},
), ),
); );
} else {
return FlowyTextButton(
emoji,
overflow: TextOverflow.visible,
fontSize: emojiSize,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: 35.0),
fillColor: Colors.transparent,
mainAxisAlignment: MainAxisAlignment.center,
onPressed: () async {
final result = await context.push<EmojiPickerResult>(
Uri(
path: MobileEmojiPickerScreen.routeName,
queryParameters: {
MobileEmojiPickerScreen.pageTitle: title,
},
).toString(),
);
if (result != null) {
onSubmitted(
result.emoji,
null,
);
}
},
);
} }
return FlowyTextButton(
emoji,
overflow: TextOverflow.visible,
fontSize: emojiSize,
padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: 35.0),
fillColor: Colors.transparent,
mainAxisAlignment: MainAxisAlignment.center,
onPressed: () async {
final result = await context.push<EmojiPickerResult>(
Uri(
path: MobileEmojiPickerScreen.routeName,
queryParameters: {MobileEmojiPickerScreen.pageTitle: title},
).toString(),
);
if (result != null) {
onSubmitted(result.emoji, null);
}
},
);
} }
} }

View File

@ -16,11 +16,11 @@ class MobileCodeLanguagePickerScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: FlowyAppBar( appBar: FlowyAppBar(titleText: LocaleKeys.titleBar_language.tr()),
titleText: LocaleKeys.titleBar_language.tr(),
),
body: SafeArea( body: SafeArea(
child: ListView.separated( child: ListView.separated(
separatorBuilder: (_, __) => const Divider(),
itemCount: defaultCodeBlockSupportedLanguages.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final language = defaultCodeBlockSupportedLanguages[index]; final language = defaultCodeBlockSupportedLanguages[index];
return SizedBox( return SizedBox(
@ -35,8 +35,6 @@ class MobileCodeLanguagePickerScreen extends StatelessWidget {
), ),
); );
}, },
separatorBuilder: (_, __) => const Divider(),
itemCount: defaultCodeBlockSupportedLanguages.length,
), ),
), ),
); );

View File

@ -1,3 +1,5 @@
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/workspace/presentation/settings/widgets/settings_appearance/font_family_setting.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/font_family_setting.dart';
@ -6,7 +8,6 @@ import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
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';
final customizeFontToolbarItem = ToolbarItem( final customizeFontToolbarItem = ToolbarItem(
id: 'editor.font', id: 'editor.font',
@ -34,9 +35,8 @@ final customizeFontToolbarItem = ToolbarItem(
Log.error('Failed to set font family: $e'); Log.error('Failed to set font family: $e');
} }
}, },
onResetFont: () async => editorState.formatDelta(selection, { onResetFont: () async => editorState
AppFlowyRichTextKeys.fontFamily: null, .formatDelta(selection, {AppFlowyRichTextKeys.fontFamily: null}),
}),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0), padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: FlowyTooltip( child: FlowyTooltip(

View File

@ -6,7 +6,6 @@ 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/base/type_option_menu_item.dart'; import 'package:appflowy/mobile/presentation/base/type_option_menu_item.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_placeholder.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
@ -14,11 +13,12 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mo
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_item/mobile_add_block_toolbar_item.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_item/mobile_add_block_toolbar_item.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_menu/_toolbar_theme.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/aa_menu/_toolbar_theme.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/startup/tasks/app_widget.dart'; import 'package:appflowy/startup/tasks/app_widget.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.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';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
final addBlockToolbarItem = AppFlowyMobileToolbarItem( final addBlockToolbarItem = AppFlowyMobileToolbarItem(
@ -45,7 +45,6 @@ final addBlockToolbarItem = AppFlowyMobileToolbarItem(
keepEditorFocusNotifier.increase(); keepEditorFocusNotifier.increase();
final didAddBlock = await showAddBlockMenu( final didAddBlock = await showAddBlockMenu(
AppGlobals.rootNavKey.currentContext!, AppGlobals.rootNavKey.currentContext!,
documentBloc: context.read<DocumentBloc>(),
editorState: editorState, editorState: editorState,
selection: selection!, selection: selection!,
); );
@ -60,33 +59,25 @@ final addBlockToolbarItem = AppFlowyMobileToolbarItem(
Future<bool?> showAddBlockMenu( Future<bool?> showAddBlockMenu(
BuildContext context, { BuildContext context, {
required DocumentBloc documentBloc,
required EditorState editorState, required EditorState editorState,
required Selection selection, required Selection selection,
}) async { }) async =>
final theme = ToolbarColorExtension.of(context); showMobileBottomSheet<bool>(
return showMobileBottomSheet<bool>( context,
context, showHeader: true,
showHeader: true, showDragHandle: true,
showDragHandle: true, showCloseButton: true,
showCloseButton: true, title: LocaleKeys.button_add.tr(),
title: LocaleKeys.button_add.tr(), barrierColor: Colors.transparent,
barrierColor: Colors.transparent, backgroundColor:
backgroundColor: theme.toolbarMenuBackgroundColor, ToolbarColorExtension.of(context).toolbarMenuBackgroundColor,
elevation: 20, elevation: 20,
enableDraggableScrollable: true, enableDraggableScrollable: true,
builder: (_) => Padding( builder: (_) => Padding(
padding: EdgeInsets.all(16 * context.scale), padding: EdgeInsets.all(16 * context.scale),
child: BlocProvider.value( child: _AddBlockMenu(selection: selection, editorState: editorState),
value: documentBloc,
child: _AddBlockMenu(
selection: selection,
editorState: editorState,
),
), ),
), );
);
}
class _AddBlockMenu extends StatelessWidget { class _AddBlockMenu extends StatelessWidget {
const _AddBlockMenu({ const _AddBlockMenu({
@ -99,12 +90,9 @@ class _AddBlockMenu extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider.value( return TypeOptionMenu<String>(
value: context.read<DocumentBloc>(), values: buildTypeOptionMenuItemValues(context),
child: TypeOptionMenu<String>( scaleFactor: context.scale,
values: buildTypeOptionMenuItemValues(context),
scaleFactor: context.scale,
),
); );
} }
@ -226,7 +214,7 @@ class _AddBlockMenu extends StatelessWidget {
onTap: (_, __) async { onTap: (_, __) async {
AppGlobals.rootNavKey.currentContext?.pop(true); AppGlobals.rootNavKey.currentContext?.pop(true);
final currentViewId = context.read<DocumentBloc>().documentId; final currentViewId = getIt<MenuSharedState>().latestOpenView?.id;
final viewId = await showPageSelectorSheet( final viewId = await showPageSelectorSheet(
context, context,
currentViewId: currentViewId, currentViewId: currentViewId,

View File

@ -24,7 +24,10 @@ class CachedRecentService {
Completer<void> _completer = Completer(); Completer<void> _completer = Completer();
ValueNotifier<List<ViewPB>> notifier = ValueNotifier(const []); ValueNotifier<List<ViewPB>> notifier = ValueNotifier(const []);
List<ViewPB> _recentViews = const [];
List<ViewPB> get _recentViews => notifier.value;
set _recentViews(List<ViewPB> value) => notifier.value = value;
final _listener = RecentViewsListener(); final _listener = RecentViewsListener();
Future<List<ViewPB>> recentViews() async { Future<List<ViewPB>> recentViews() async {
@ -35,7 +38,6 @@ class CachedRecentService {
_listener.start(recentViewsUpdated: _recentViewsUpdated); _listener.start(recentViewsUpdated: _recentViewsUpdated);
final result = await _readRecentViews(); final result = await _readRecentViews();
_recentViews = result.toNullable()?.items ?? const []; _recentViews = result.toNullable()?.items ?? const [];
notifier.value = _recentViews;
_completer.complete(); _completer.complete();
return _recentViews; return _recentViews;
@ -64,6 +66,7 @@ class CachedRecentService {
} }
Future<void> dispose() async { Future<void> dispose() async {
notifier.dispose();
await _listener.stop(); await _listener.stop();
} }

View File

@ -37,6 +37,10 @@ class RecentViewsBloc extends Bloc<RecentViewsEvent, RecentViewsState> {
fetchRecentViews: (e) async { fetchRecentViews: (e) async {
emit(state.copyWith(views: await _service.recentViews())); emit(state.copyWith(views: await _service.recentViews()));
}, },
resetRecentViews: (e) async {
await _service.reset();
add(const RecentViewsEvent.fetchRecentViews());
},
); );
}, },
); );
@ -54,13 +58,13 @@ class RecentViewsEvent with _$RecentViewsEvent {
const factory RecentViewsEvent.removeRecentViews(List<String> viewIds) = const factory RecentViewsEvent.removeRecentViews(List<String> viewIds) =
RemoveRecentViews; RemoveRecentViews;
const factory RecentViewsEvent.fetchRecentViews() = FetchRecentViews; const factory RecentViewsEvent.fetchRecentViews() = FetchRecentViews;
const factory RecentViewsEvent.resetRecentViews() = ResetRecentViews;
} }
@freezed @freezed
class RecentViewsState with _$RecentViewsState { class RecentViewsState with _$RecentViewsState {
const factory RecentViewsState({ const factory RecentViewsState({required List<ViewPB> views}) =
required List<ViewPB> views, _RecentViewsState;
}) = _RecentViewsState;
factory RecentViewsState.initial() => const RecentViewsState(views: []); factory RecentViewsState.initial() => const RecentViewsState(views: []);
} }

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:appflowy/core/frameless_window.dart'; import 'package:appflowy/core/frameless_window.dart';
import 'package:appflowy/plugins/blank/blank.dart'; import 'package:appflowy/plugins/blank/blank.dart';
@ -110,9 +111,7 @@ class FadingIndexedStack extends StatefulWidget {
super.key, super.key,
required this.index, required this.index,
required this.children, required this.children,
this.duration = const Duration( this.duration = const Duration(milliseconds: 250),
milliseconds: 250,
),
}); });
final int index; final int index;
@ -135,8 +134,10 @@ class FadingIndexedStackState extends State<FadingIndexedStack> {
@override @override
void didUpdateWidget(FadingIndexedStack oldWidget) { void didUpdateWidget(FadingIndexedStack oldWidget) {
if (oldWidget.index == widget.index) return; if (oldWidget.index == widget.index) return;
setState(() => _targetOpacity = 0); _targetOpacity = 0;
Future.delayed(1.milliseconds, () => setState(() => _targetOpacity = 1)); SchedulerBinding.instance.addPostFrameCallback(
(_) => setState(() => _targetOpacity = 1),
);
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
} }

View File

@ -1,12 +1,14 @@
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/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';
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart'; import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.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_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.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';
class FavoriteFolder extends StatelessWidget { class FavoriteFolder extends StatelessWidget {
@ -98,6 +100,8 @@ class _FavoriteHeaderState extends State<FavoriteHeader> {
children: [ children: [
FlowyTextButton( FlowyTextButton(
LocaleKeys.sideBar_favorites.tr(), LocaleKeys.sideBar_favorites.tr(),
fontColor: AFThemeExtension.of(context).textColor,
fontHoverColor: Theme.of(context).colorScheme.onSurface,
tooltip: LocaleKeys.sideBar_clickToHideFavorites.tr(), tooltip: LocaleKeys.sideBar_clickToHideFavorites.tr(),
constraints: const BoxConstraints(maxHeight: iconSize), constraints: const BoxConstraints(maxHeight: iconSize),
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),

View File

@ -43,6 +43,7 @@ class _FolderHeaderState extends State<FolderHeader> {
minHeight: iconSize + textPadding * 2, minHeight: iconSize + textPadding * 2,
), ),
fontColor: AFThemeExtension.of(context).textColor, fontColor: AFThemeExtension.of(context).textColor,
fontHoverColor: Theme.of(context).colorScheme.onSurface,
padding: const EdgeInsets.all(textPadding), padding: const EdgeInsets.all(textPadding),
fillColor: Colors.transparent, fillColor: Colors.transparent,
onPressed: widget.onPressed, onPressed: widget.onPressed,

View File

@ -178,9 +178,7 @@ class HomeSideBar extends StatelessWidget {
} }
class _Sidebar extends StatefulWidget { class _Sidebar extends StatefulWidget {
const _Sidebar({ const _Sidebar({required this.userProfile});
required this.userProfile,
});
final UserProfilePB userProfile; final UserProfilePB userProfile;
@ -222,10 +220,7 @@ class _SidebarState extends State<_Sidebar> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// top menu // top menu
const Padding( const Padding(padding: menuHorizontalInset, child: SidebarTopMenu()),
padding: menuHorizontalInset,
child: SidebarTopMenu(),
),
// user or workspace, setting // user or workspace, setting
Padding( Padding(
padding: menuHorizontalInset, padding: menuHorizontalInset,
@ -245,8 +240,9 @@ class _SidebarState extends State<_Sidebar> {
// scrollable document list // scrollable document list
Expanded( Expanded(
child: Padding( child: Padding(
padding: menuHorizontalInset, padding: menuHorizontalInset - const EdgeInsets.only(right: 6),
child: SingleChildScrollView( child: SingleChildScrollView(
padding: const EdgeInsets.only(right: 6),
controller: _scrollController, controller: _scrollController,
physics: const ClampingScrollPhysics(), physics: const ClampingScrollPhysics(),
child: SidebarFolder( child: SidebarFolder(

View File

@ -1,3 +1,5 @@
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/startup/startup.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart'; import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
@ -10,7 +12,6 @@ import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/_sectio
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
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:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class SidebarFolder extends StatelessWidget { class SidebarFolder extends StatelessWidget {
@ -38,10 +39,7 @@ class SidebarFolder extends StatelessWidget {
} }
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 10),
child: FavoriteFolder( child: FavoriteFolder(views: state.views),
// remove the duplicate views
views: state.views,
),
); );
}, },
), ),
@ -52,30 +50,27 @@ class SidebarFolder extends StatelessWidget {
final isCollaborativeWorkspace = final isCollaborativeWorkspace =
context.read<UserWorkspaceBloc>().state.isCollabWorkspaceOn; context.read<UserWorkspaceBloc>().state.isCollabWorkspaceOn;
// only show public and private section if the workspace is collaborative
return Column( return Column(
children: children: isCollaborativeWorkspace
// only show public and private section if the workspace is collaborative ? [
isCollaborativeWorkspace // public
? [ const VSpace(10),
// public PublicSectionFolder(views: state.section.publicViews),
const VSpace(10),
PublicSectionFolder(
views: state.section.publicViews,
),
// private // private
const VSpace(10), const VSpace(10),
PrivateSectionFolder( PrivateSectionFolder(
views: state.section.privateViews, views: state.section.privateViews,
), ),
] ]
: [ : [
// personal // personal
const VSpace(10), const VSpace(10),
PersonalSectionFolder( PersonalSectionFolder(
views: state.section.publicViews, views: state.section.publicViews,
), ),
], ],
); );
}, },
), ),
@ -87,10 +82,8 @@ class SidebarFolder extends StatelessWidget {
} }
class PrivateSectionFolder extends SectionFolder { class PrivateSectionFolder extends SectionFolder {
PrivateSectionFolder({ PrivateSectionFolder({super.key, required super.views})
super.key, : super(
required super.views,
}) : super(
title: LocaleKeys.sideBar_private.tr(), title: LocaleKeys.sideBar_private.tr(),
categoryType: FolderCategoryType.private, categoryType: FolderCategoryType.private,
expandButtonTooltip: LocaleKeys.sideBar_clickToHidePrivate.tr(), expandButtonTooltip: LocaleKeys.sideBar_clickToHidePrivate.tr(),
@ -99,10 +92,8 @@ class PrivateSectionFolder extends SectionFolder {
} }
class PublicSectionFolder extends SectionFolder { class PublicSectionFolder extends SectionFolder {
PublicSectionFolder({ PublicSectionFolder({super.key, required super.views})
super.key, : super(
required super.views,
}) : super(
title: LocaleKeys.sideBar_workspace.tr(), title: LocaleKeys.sideBar_workspace.tr(),
categoryType: FolderCategoryType.public, categoryType: FolderCategoryType.public,
expandButtonTooltip: LocaleKeys.sideBar_clickToHideWorkspace.tr(), expandButtonTooltip: LocaleKeys.sideBar_clickToHideWorkspace.tr(),
@ -111,10 +102,8 @@ class PublicSectionFolder extends SectionFolder {
} }
class PersonalSectionFolder extends SectionFolder { class PersonalSectionFolder extends SectionFolder {
PersonalSectionFolder({ PersonalSectionFolder({super.key, required super.views})
super.key, : super(
required super.views,
}) : super(
title: LocaleKeys.sideBar_personal.tr(), title: LocaleKeys.sideBar_personal.tr(),
categoryType: FolderCategoryType.public, categoryType: FolderCategoryType.public,
expandButtonTooltip: LocaleKeys.sideBar_clickToHidePersonal.tr(), expandButtonTooltip: LocaleKeys.sideBar_clickToHidePersonal.tr(),

View File

@ -1,3 +1,5 @@
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/base/emoji/emoji_text.dart'; import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
@ -24,7 +26,6 @@ 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/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.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';
typedef ViewItemOnSelected = void Function(ViewPB, BuildContext); typedef ViewItemOnSelected = void Function(ViewPB, BuildContext);

View File

@ -1,10 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.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/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart'; import 'package:appflowy/plugins/base/icon/icon_picker.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart'; import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/user/settings_user_bloc.dart'; import 'package:appflowy/workspace/application/user/settings_user_bloc.dart';
@ -14,18 +13,16 @@ import 'package:appflowy/workspace/presentation/settings/shared/settings_categor
import 'package:appflowy/workspace/presentation/settings/shared/settings_category_spacer.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_category_spacer.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_header.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_header.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_input_field.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_input_field.dart';
import 'package:appflowy/workspace/presentation/settings/shared/single_setting_action.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_third_party_login.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/setting_third_party_login.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart'; import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
import 'package:appflowy_backend/protobuf/flowy-user/auth.pbenum.dart'; import 'package:appflowy_backend/protobuf/flowy-user/auth.pbenum.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:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -51,15 +48,6 @@ class SettingsAccountView extends StatefulWidget {
class _SettingsAccountViewState extends State<SettingsAccountView> { class _SettingsAccountViewState extends State<SettingsAccountView> {
late String userName = widget.userProfile.name; late String userName = widget.userProfile.name;
late final TextEditingController _emailController = TextEditingController(
text: widget.userProfile.email,
);
@override
void dispose() {
_emailController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -67,11 +55,7 @@ class _SettingsAccountViewState extends State<SettingsAccountView> {
create: (context) => create: (context) =>
getIt<SettingsUserViewBloc>(param1: widget.userProfile) getIt<SettingsUserViewBloc>(param1: widget.userProfile)
..add(const SettingsUserEvent.initial()), ..add(const SettingsUserEvent.initial()),
child: BlocConsumer<SettingsUserViewBloc, SettingsUserState>( child: BlocBuilder<SettingsUserViewBloc, SettingsUserState>(
listenWhen: (previous, current) =>
previous.userProfile.email != current.userProfile.email,
listener: (context, state) =>
_emailController.text = state.userProfile.email,
builder: (context, state) { builder: (context, state) {
return SettingsBody( return SettingsBody(
children: [ children: [
@ -97,45 +81,47 @@ class _SettingsAccountViewState extends State<SettingsAccountView> {
), ),
], ],
), ),
// Only show change email if the user is authenticated and not using local auth
if (isAuthEnabled && // Enable when/if we need change email feature
state.userProfile.authenticator != AuthenticatorPB.Local) ...[ // // Only show change email if the user is authenticated and not using local auth
const SettingsCategorySpacer(), // if (isAuthEnabled &&
SettingsCategory( // state.userProfile.authenticator != AuthenticatorPB.Local) ...[
title: LocaleKeys.settings_accountPage_email_title.tr(), // const SettingsCategorySpacer(),
children: [ // SettingsCategory(
SingleSettingAction( // title: LocaleKeys.settings_accountPage_email_title.tr(),
label: state.userProfile.email, // children: [
buttonLabel: LocaleKeys // SingleSettingAction(
.settings_accountPage_email_actions_change // label: state.userProfile.email,
.tr(), // buttonLabel: LocaleKeys
onPressed: () => SettingsAlertDialog( // .settings_accountPage_email_actions_change
title: LocaleKeys // .tr(),
.settings_accountPage_email_actions_change // onPressed: () => SettingsAlertDialog(
.tr(), // title: LocaleKeys
confirmLabel: LocaleKeys.button_save.tr(), // .settings_accountPage_email_actions_change
confirm: () { // .tr(),
context.read<SettingsUserViewBloc>().add( // confirmLabel: LocaleKeys.button_save.tr(),
SettingsUserEvent.updateUserEmail( // confirm: () {
_emailController.text, // context.read<SettingsUserViewBloc>().add(
), // SettingsUserEvent.updateUserEmail(
); // _emailController.text,
Navigator.of(context).pop(); // ),
}, // );
children: [ // Navigator.of(context).pop();
SettingsInputField( // },
label: LocaleKeys.settings_accountPage_email_title // children: [
.tr(), // SettingsInputField(
value: state.userProfile.email, // label: LocaleKeys.settings_accountPage_email_title
hideActions: true, // .tr(),
textController: _emailController, // value: state.userProfile.email,
), // hideActions: true,
], // textController: _emailController,
).show(context), // ),
), // ],
], // ).show(context),
), // ),
], // ],
// ),
// ],
/// Enable when we have change password feature and 2FA /// Enable when we have change password feature and 2FA
// const SettingsCategorySpacer(), // const SettingsCategorySpacer(),
@ -259,7 +245,9 @@ class SignInOutButton extends StatelessWidget {
hoverColor: const Color(0xFF005483), hoverColor: const Color(0xFF005483),
fontHoverColor: Colors.white, fontHoverColor: Colors.white,
onPressed: () => SettingsAlertDialog( onPressed: () => SettingsAlertDialog(
title: LocaleKeys.settings_accountPage_login_loginLabel.tr(), title: signIn
? LocaleKeys.settings_accountPage_login_loginLabel.tr()
: LocaleKeys.settings_accountPage_login_logoutLabel.tr(),
subtitle: signIn subtitle: signIn
? null ? null
: switch (userProfile.encryptionType) { : switch (userProfile.encryptionType) {
@ -303,6 +291,7 @@ class UserProfileSetting extends StatefulWidget {
} }
class _UserProfileSettingState extends State<UserProfileSetting> { class _UserProfileSettingState extends State<UserProfileSetting> {
late final _nameController = TextEditingController(text: widget.name);
late final FocusNode focusNode; late final FocusNode focusNode;
bool isEditing = false; bool isEditing = false;
bool isHovering = false; bool isHovering = false;
@ -314,14 +303,20 @@ class _UserProfileSettingState extends State<UserProfileSetting> {
onKeyEvent: (_, event) { onKeyEvent: (_, event) {
if (event is KeyDownEvent && if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.escape && event.logicalKey == LogicalKeyboardKey.escape &&
isEditing) { isEditing &&
mounted) {
setState(() => isEditing = false); setState(() => isEditing = false);
return KeyEventResult.handled; return KeyEventResult.handled;
} }
return KeyEventResult.ignored; return KeyEventResult.ignored;
}, },
); )..addListener(() {
if (!focusNode.hasFocus && isEditing && mounted) {
widget.onSave?.call(_nameController.text);
setState(() => isEditing = false);
}
});
} }
@override @override
@ -335,69 +330,28 @@ class _UserProfileSettingState extends State<UserProfileSetting> {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Stack( GestureDetector(
children: [ behavior: HitTestBehavior.opaque,
GestureDetector( onTap: () => _showIconPickerDialog(context),
behavior: HitTestBehavior.opaque, child: FlowyHover(
onTap: () => _showIconPickerDialog(context), resetHoverOnRebuild: false,
child: FlowyHover( onHover: (state) => setState(() => isHovering = state),
resetHoverOnRebuild: false, style: HoverStyle(
onHover: (state) => setState(() => isHovering = state), hoverColor: Colors.transparent,
style: HoverStyle( borderRadius: BorderRadius.circular(100),
hoverColor: Colors.transparent, ),
borderRadius: BorderRadius.circular(100), child: FlowyTooltip(
), message: LocaleKeys
child: Column( .settings_accountPage_general_changeProfilePicture
mainAxisSize: MainAxisSize.min, .tr(),
children: [ child: UserAvatar(
UserAvatar( iconUrl: widget.iconUrl,
iconUrl: widget.iconUrl, name: widget.name,
name: widget.name, isLarge: true,
isLarge: true, isHovering: isHovering,
isHovering: isHovering,
),
const VSpace(4),
FlowyText.regular(
LocaleKeys
.settings_accountPage_general_changeProfilePicture
.tr(),
color: AFThemeExtension.of(context).textColor,
),
],
),
), ),
), ),
if (widget.iconUrl.isNotEmpty) ),
Positioned(
right: 0,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => context
.read<SettingsUserViewBloc>()
.add(const SettingsUserEvent.removeUserIcon()),
child: DecoratedBox(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
shape: BoxShape.circle,
),
child: FlowyHover(
resetHoverOnRebuild: false,
style: const HoverStyle(
borderRadius: BorderRadius.all(Radius.circular(24)),
hoverColor: Color(0xFF005483),
),
builder: (_, __) => Padding(
padding: const EdgeInsets.all(4),
child: FlowySvg(
FlowySvgs.close_s,
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
),
),
),
],
), ),
const HSpace(16), const HSpace(16),
if (!isEditing) ...[ if (!isEditing) ...[
@ -430,6 +384,7 @@ class _UserProfileSettingState extends State<UserProfileSetting> {
] else ...[ ] else ...[
Flexible( Flexible(
child: SettingsInputField( child: SettingsInputField(
textController: _nameController,
value: widget.name, value: widget.name,
focusNode: focusNode..requestFocus(), focusNode: focusNode..requestFocus(),
onCancel: () => setState(() => isEditing = false), onCancel: () => setState(() => isEditing = false),
@ -448,20 +403,16 @@ class _UserProfileSettingState extends State<UserProfileSetting> {
return showDialog( return showDialog(
context: context, context: context,
builder: (dialogContext) => SimpleDialog( builder: (dialogContext) => SimpleDialog(
title: FlowyText.medium(
LocaleKeys.settings_user_selectAnIcon.tr(),
fontSize: FontSizes.s16,
),
children: [ children: [
Container( Container(
height: 380, height: 380,
width: 360, width: 360,
margin: const EdgeInsets.symmetric(horizontal: 12), margin: const EdgeInsets.symmetric(horizontal: 12),
child: FlowyEmojiPicker( child: FlowyIconPicker(
onEmojiSelected: (_, emoji) { onSelected: (result) {
context context.read<SettingsUserViewBloc>().add(
.read<SettingsUserViewBloc>() SettingsUserEvent.updateUserIcon(iconUrl: result.emoji),
.add(SettingsUserEvent.updateUserIcon(iconUrl: emoji)); );
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
}, },
), ),

View File

@ -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/workspace/application/export/document_exporter.dart'; import 'package:appflowy/workspace/application/export/document_exporter.dart';
import 'package:appflowy/workspace/application/settings/settings_file_exporter_cubit.dart'; import 'package:appflowy/workspace/application/settings/settings_file_exporter_cubit.dart';
@ -13,8 +15,8 @@ import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_result/appflowy_result.dart'; import 'package:appflowy_result/appflowy_result.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/file_picker/file_picker_service.dart'; import 'package:flowy_infra/file_picker/file_picker_service.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart' hide WidgetBuilder; import 'package:flowy_infra_ui/flowy_infra_ui.dart' hide WidgetBuilder;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
@ -64,6 +66,7 @@ class _FileExporterWidgetState extends State<FileExporterWidget> {
.every((element) => element) .every((element) => element)
? LocaleKeys.settings_files_deselectAll.tr() ? LocaleKeys.settings_files_deselectAll.tr()
: LocaleKeys.settings_files_selectAll.tr(), : LocaleKeys.settings_files_selectAll.tr(),
fontColor: AFThemeExtension.of(context).textColor,
onPressed: () { onPressed: () {
context context
.read<SettingsFileExporterCubit>() .read<SettingsFileExporterCubit>()
@ -93,13 +96,13 @@ class _FileExporterWidgetState extends State<FileExporterWidget> {
const Spacer(), const Spacer(),
FlowyTextButton( FlowyTextButton(
LocaleKeys.button_cancel.tr(), LocaleKeys.button_cancel.tr(),
onPressed: () { fontColor: AFThemeExtension.of(context).textColor,
Navigator.of(context).pop(); onPressed: () => Navigator.of(context).pop(),
},
), ),
const HSpace(8), const HSpace(8),
FlowyTextButton( FlowyTextButton(
LocaleKeys.button_ok.tr(), LocaleKeys.button_ok.tr(),
fontColor: AFThemeExtension.of(context).textColor,
onPressed: () async { onPressed: () async {
await getIt<FilePickerService>() await getIt<FilePickerService>()
.getDirectoryPath() .getDirectoryPath()

View File

@ -1,3 +1,5 @@
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';
@ -8,8 +10,8 @@ import 'package:appflowy/workspace/application/settings/appearance/appearance_cu
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:collection/collection.dart'; 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_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -208,9 +210,7 @@ class _FontFamilyDropDownState extends State<FontFamilyDropDown> {
} }
class _ResetFontButton extends SliverPersistentHeaderDelegate { class _ResetFontButton extends SliverPersistentHeaderDelegate {
_ResetFontButton({ _ResetFontButton({this.onPressed});
this.onPressed,
});
final VoidCallback? onPressed; final VoidCallback? onPressed;
@ -224,6 +224,9 @@ class _ResetFontButton extends SliverPersistentHeaderDelegate {
padding: const EdgeInsets.only(right: 8, bottom: 8.0), padding: const EdgeInsets.only(right: 8, bottom: 8.0),
child: FlowyTextButton( child: FlowyTextButton(
LocaleKeys.document_toolbar_resetToDefaultFont.tr(), LocaleKeys.document_toolbar_resetToDefaultFont.tr(),
fontColor: AFThemeExtension.of(context).textColor,
fontHoverColor: Theme.of(context).colorScheme.onSurface,
fontSize: 12,
onPressed: onPressed, onPressed: onPressed,
), ),
); );

View File

@ -9,6 +9,7 @@ import 'package:appflowy/workspace/presentation/settings/shared/settings_body.da
import 'package:appflowy/workspace/presentation/settings/shared/settings_header.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_header.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.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_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -75,6 +76,7 @@ class ShortcutsListView extends StatelessWidget {
const Spacer(), const Spacer(),
FlowyTextButton( FlowyTextButton(
LocaleKeys.settings_shortcuts_resetToDefault.tr(), LocaleKeys.settings_shortcuts_resetToDefault.tr(),
fontColor: AFThemeExtension.of(context).textColor,
onPressed: () => context.read<ShortcutsCubit>().resetToDefault(), onPressed: () => context.read<ShortcutsCubit>().resetToDefault(),
), ),
], ],
@ -109,9 +111,8 @@ class ShortcutsListTile extends StatelessWidget {
FlowyTextButton( FlowyTextButton(
shortcutEvent.command, shortcutEvent.command,
fillColor: Colors.transparent, fillColor: Colors.transparent,
onPressed: () { fontColor: AFThemeExtension.of(context).textColor,
showKeyListenerDialog(context); onPressed: () => showKeyListenerDialog(context),
},
), ),
], ],
), ),

View File

@ -8,7 +8,6 @@ import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dar
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.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_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
class SettingsMenu extends StatelessWidget { class SettingsMenu extends StatelessWidget {
@ -59,60 +58,42 @@ class SettingsMenu extends StatelessWidget {
page: SettingsPage.appearance, page: SettingsPage.appearance,
selectedPage: currentPage, selectedPage: currentPage,
label: LocaleKeys.settings_menu_appearance.tr(), label: LocaleKeys.settings_menu_appearance.tr(),
icon: Icon( icon: const Icon(Icons.brightness_4),
Icons.brightness_4,
color: AFThemeExtension.of(context).textColor,
),
changeSelectedPage: changeSelectedPage, changeSelectedPage: changeSelectedPage,
), ),
SettingsMenuElement( SettingsMenuElement(
page: SettingsPage.language, page: SettingsPage.language,
selectedPage: currentPage, selectedPage: currentPage,
label: LocaleKeys.settings_menu_language.tr(), label: LocaleKeys.settings_menu_language.tr(),
icon: Icon( icon: const Icon(Icons.translate),
Icons.translate,
color: AFThemeExtension.of(context).textColor,
),
changeSelectedPage: changeSelectedPage, changeSelectedPage: changeSelectedPage,
), ),
SettingsMenuElement( SettingsMenuElement(
page: SettingsPage.files, page: SettingsPage.files,
selectedPage: currentPage, selectedPage: currentPage,
label: LocaleKeys.settings_menu_files.tr(), label: LocaleKeys.settings_menu_files.tr(),
icon: Icon( icon: const Icon(Icons.file_present_outlined),
Icons.file_present_outlined,
color: AFThemeExtension.of(context).textColor,
),
changeSelectedPage: changeSelectedPage, changeSelectedPage: changeSelectedPage,
), ),
SettingsMenuElement( SettingsMenuElement(
page: SettingsPage.notifications, page: SettingsPage.notifications,
selectedPage: currentPage, selectedPage: currentPage,
label: LocaleKeys.settings_menu_notifications.tr(), label: LocaleKeys.settings_menu_notifications.tr(),
icon: Icon( icon: const Icon(Icons.notifications_outlined),
Icons.notifications_outlined,
color: AFThemeExtension.of(context).textColor,
),
changeSelectedPage: changeSelectedPage, changeSelectedPage: changeSelectedPage,
), ),
SettingsMenuElement( SettingsMenuElement(
page: SettingsPage.cloud, page: SettingsPage.cloud,
selectedPage: currentPage, selectedPage: currentPage,
label: LocaleKeys.settings_menu_cloudSettings.tr(), label: LocaleKeys.settings_menu_cloudSettings.tr(),
icon: Icon( icon: const Icon(Icons.sync),
Icons.sync,
color: AFThemeExtension.of(context).textColor,
),
changeSelectedPage: changeSelectedPage, changeSelectedPage: changeSelectedPage,
), ),
SettingsMenuElement( SettingsMenuElement(
page: SettingsPage.shortcuts, page: SettingsPage.shortcuts,
selectedPage: currentPage, selectedPage: currentPage,
label: LocaleKeys.settings_shortcuts_shortcutsLabel.tr(), label: LocaleKeys.settings_shortcuts_shortcutsLabel.tr(),
icon: Icon( icon: const Icon(Icons.cut),
Icons.cut,
color: AFThemeExtension.of(context).textColor,
),
changeSelectedPage: changeSelectedPage, changeSelectedPage: changeSelectedPage,
), ),
if (FeatureFlag.membersSettings.isOn && if (FeatureFlag.membersSettings.isOn &&
@ -122,10 +103,7 @@ class SettingsMenu extends StatelessWidget {
page: SettingsPage.member, page: SettingsPage.member,
selectedPage: currentPage, selectedPage: currentPage,
label: LocaleKeys.settings_appearance_members_label.tr(), label: LocaleKeys.settings_appearance_members_label.tr(),
icon: Icon( icon: const Icon(Icons.people),
Icons.people,
color: AFThemeExtension.of(context).textColor,
),
changeSelectedPage: changeSelectedPage, changeSelectedPage: changeSelectedPage,
), ),
if (kDebugMode) if (kDebugMode)
@ -134,10 +112,7 @@ class SettingsMenu extends StatelessWidget {
page: SettingsPage.featureFlags, page: SettingsPage.featureFlags,
selectedPage: currentPage, selectedPage: currentPage,
label: 'Feature Flags', label: 'Feature Flags',
icon: Icon( icon: const Icon(Icons.flag),
Icons.flag,
color: AFThemeExtension.of(context).textColor,
),
changeSelectedPage: changeSelectedPage, changeSelectedPage: changeSelectedPage,
), ),
], ],

View File

@ -31,9 +31,13 @@ class SettingsMenuElement extends StatelessWidget {
hoverColor: AFThemeExtension.of(context).greySelect, hoverColor: AFThemeExtension.of(context).greySelect,
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
), ),
child: ListTile( builder: (_, isHovering) => ListTile(
dense: true, dense: true,
leading: icon, leading: iconWidget(
isHovering || page == selectedPage
? Theme.of(context).colorScheme.onSurface
: AFThemeExtension.of(context).textColor,
),
onTap: () => changeSelectedPage(page), onTap: () => changeSelectedPage(page),
selected: page == selectedPage, selected: page == selectedPage,
selectedColor: Theme.of(context).colorScheme.onSurface, selectedColor: Theme.of(context).colorScheme.onSurface,
@ -53,4 +57,9 @@ class SettingsMenuElement extends StatelessWidget {
), ),
); );
} }
Widget iconWidget(Color color) => IconTheme(
data: IconThemeData(color: color),
child: icon,
);
} }

View File

@ -324,7 +324,7 @@
"description": "Customize your profile, manage account security and AI API keys, or login into your account.", "description": "Customize your profile, manage account security and AI API keys, or login into your account.",
"general": { "general": {
"title": "Account name & profile image", "title": "Account name & profile image",
"changeProfilePicture": "Change" "changeProfilePicture": "Change profile picture"
}, },
"email": { "email": {
"title": "Email", "title": "Email",