mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: toggle notifications on/off (#3672)
This commit is contained in:
parent
bc8f35d7db
commit
ebe112581d
@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
|
||||
|
@ -7,7 +7,7 @@ import 'package:appflowy/plugins/inline_actions/handlers/inline_page_reference.d
|
||||
import 'package:appflowy/plugins/inline_actions/handlers/reminder_reference.dart';
|
||||
import 'package:appflowy/plugins/inline_actions/inline_actions_command.dart';
|
||||
import 'package:appflowy/plugins/inline_actions/inline_actions_service.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.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/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_button.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/option_action.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/settings/date_time/date_format_ext.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/date_picker_dialog.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
|
@ -24,6 +24,7 @@ import 'package:appflowy/user/presentation/router.dart';
|
||||
import 'package:appflowy/workspace/application/edit_panel/edit_panel_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/local_notifications/notification_action_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/settings/notifications/notification_settings_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/user/prelude.dart';
|
||||
@ -168,14 +169,22 @@ void _resolveHomeDeps(GetIt getIt) {
|
||||
|
||||
getIt.registerLazySingleton<TabsBloc>(() => TabsBloc());
|
||||
|
||||
getIt.registerSingleton<ReminderBloc>(ReminderBloc());
|
||||
getIt.registerSingleton<NotificationSettingsCubit>(
|
||||
NotificationSettingsCubit(),
|
||||
);
|
||||
|
||||
getIt.registerSingleton<ReminderBloc>(
|
||||
ReminderBloc(notificationSettings: getIt<NotificationSettingsCubit>()),
|
||||
);
|
||||
}
|
||||
|
||||
void _resolveFolderDeps(GetIt getIt) {
|
||||
//workspace
|
||||
getIt.registerFactoryParam<WorkspaceListener, UserProfilePB, String>(
|
||||
(user, workspaceId) =>
|
||||
WorkspaceListener(user: user, workspaceId: workspaceId),
|
||||
(user, workspaceId) => WorkspaceListener(
|
||||
user: user,
|
||||
workspaceId: workspaceId,
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<ViewBloc, ViewPB, void>(
|
||||
|
@ -1,19 +1,23 @@
|
||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/local_notifications/notification_service.dart';
|
||||
import 'package:appflowy/startup/tasks/prelude.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:appflowy/workspace/application/settings/notifications/notification_settings_cubit.dart';
|
||||
|
||||
import 'prelude.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../user/application/user_settings_service.dart';
|
||||
import '../../workspace/application/appearance.dart';
|
||||
import '../startup.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
|
||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/local_notifications/notification_service.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/user/application/user_settings_service.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
|
||||
class InitAppWidgetTask extends LaunchTask {
|
||||
const InitAppWidgetTask();
|
||||
@ -95,8 +99,8 @@ class ApplicationWidget extends StatefulWidget {
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
final AppearanceSettingsPB appearanceSetting;
|
||||
final AppTheme appTheme;
|
||||
final AppearanceSettingsPB appearanceSetting;
|
||||
final DateTimeSettingsPB dateTimeSettings;
|
||||
|
||||
@override
|
||||
@ -125,6 +129,9 @@ class _ApplicationWidgetState extends State<ApplicationWidget> {
|
||||
widget.appTheme,
|
||||
)..readLocaleWhenAppLaunch(context),
|
||||
),
|
||||
BlocProvider<NotificationSettingsCubit>(
|
||||
create: (_) => getIt<NotificationSettingsCubit>(),
|
||||
),
|
||||
BlocProvider<DocumentAppearanceCubit>(
|
||||
create: (_) => DocumentAppearanceCubit()..fetch(),
|
||||
),
|
||||
|
@ -6,6 +6,7 @@ import 'package:appflowy/user/application/reminder/reminder_service.dart';
|
||||
import 'package:appflowy/workspace/application/local_notifications/notification_action.dart';
|
||||
import 'package:appflowy/workspace/application/local_notifications/notification_action_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/local_notifications/notification_service.dart';
|
||||
import 'package:appflowy/workspace/application/settings/notifications/notification_settings_cubit.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
@ -18,11 +19,16 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'reminder_bloc.freezed.dart';
|
||||
|
||||
class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
|
||||
final NotificationSettingsCubit _notificationSettings;
|
||||
|
||||
late final NotificationActionBloc actionBloc;
|
||||
late final ReminderService reminderService;
|
||||
late final Timer timer;
|
||||
|
||||
ReminderBloc() : super(ReminderState()) {
|
||||
ReminderBloc({
|
||||
required NotificationSettingsCubit notificationSettings,
|
||||
}) : _notificationSettings = notificationSettings,
|
||||
super(ReminderState()) {
|
||||
actionBloc = getIt<NotificationActionBloc>();
|
||||
reminderService = const ReminderService();
|
||||
timer = _periodicCheck();
|
||||
@ -124,16 +130,18 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
|
||||
);
|
||||
|
||||
if (scheduledAt.isBefore(now)) {
|
||||
NotificationMessage(
|
||||
identifier: reminder.id,
|
||||
title: LocaleKeys.reminderNotification_title.tr(),
|
||||
body: LocaleKeys.reminderNotification_message.tr(),
|
||||
onClick: () => actionBloc.add(
|
||||
NotificationActionEvent.performAction(
|
||||
action: NotificationAction(objectId: reminder.objectId),
|
||||
if (_notificationSettings.state.isNotificationsEnabled) {
|
||||
NotificationMessage(
|
||||
identifier: reminder.id,
|
||||
title: LocaleKeys.reminderNotification_title.tr(),
|
||||
body: LocaleKeys.reminderNotification_message.tr(),
|
||||
onClick: () => actionBloc.add(
|
||||
NotificationActionEvent.performAction(
|
||||
action: NotificationAction(objectId: reminder.objectId),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
add(
|
||||
ReminderEvent.update(
|
||||
|
@ -41,4 +41,20 @@ class UserSettingsBackendService {
|
||||
) async {
|
||||
return (await UserEventSetDateTimeSettings(settings).send()).swap();
|
||||
}
|
||||
|
||||
Future<Either<FlowyError, Unit>> setNotificationSettings(
|
||||
NotificationSettingsPB settings,
|
||||
) async {
|
||||
return (await UserEventSetNotificationSettings(settings).send()).swap();
|
||||
}
|
||||
|
||||
Future<NotificationSettingsPB> getNotificationSettings() async {
|
||||
final result = await UserEventGetNotificationSettings().send();
|
||||
|
||||
return result.fold(
|
||||
(NotificationSettingsPB setting) => setting,
|
||||
(error) =>
|
||||
throw FlowySDKException(ExceptionType.AppearanceSettingsIsEmpty),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/application/sign_in_bloc.dart';
|
||||
import 'package:appflowy/user/presentation/presentation.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
|
@ -8,7 +8,7 @@ import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
import 'package:appflowy/user/application/historical_user_bloc.dart';
|
||||
import 'package:appflowy/user/presentation/router.dart';
|
||||
import 'package:appflowy/user/presentation/widgets/widgets.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:appflowy/user/application/user_listener.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/edit_panel/edit_context.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/workspace.pb.dart'
|
||||
show WorkspaceSettingPB;
|
||||
|
@ -16,33 +16,40 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
part 'appearance.freezed.dart';
|
||||
part 'appearance_cubit.freezed.dart';
|
||||
|
||||
const _white = Color(0xFFFFFFFF);
|
||||
|
||||
/// [AppearanceSettingsCubit] is used to modify the appearance of AppFlowy.
|
||||
/// It includes the [AppTheme], [ThemeMode], [TextStyles] and [Locale].
|
||||
/// It includes:
|
||||
/// - [AppTheme]
|
||||
/// - [ThemeMode]
|
||||
/// - [TextStyle]'s
|
||||
/// - [Locale]
|
||||
/// - [UserDateFormatPB]
|
||||
/// - [UserTimeFormatPB]
|
||||
///
|
||||
class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
final AppearanceSettingsPB _setting;
|
||||
final AppearanceSettingsPB _appearanceSettings;
|
||||
final DateTimeSettingsPB _dateTimeSettings;
|
||||
|
||||
AppearanceSettingsCubit(
|
||||
AppearanceSettingsPB setting,
|
||||
AppearanceSettingsPB appearanceSettings,
|
||||
DateTimeSettingsPB dateTimeSettings,
|
||||
AppTheme appTheme,
|
||||
) : _setting = setting,
|
||||
) : _appearanceSettings = appearanceSettings,
|
||||
_dateTimeSettings = dateTimeSettings,
|
||||
super(
|
||||
AppearanceSettingsState.initial(
|
||||
appTheme,
|
||||
setting.themeMode,
|
||||
setting.font,
|
||||
setting.monospaceFont,
|
||||
setting.layoutDirection,
|
||||
setting.textDirection,
|
||||
setting.locale,
|
||||
setting.isMenuCollapsed,
|
||||
setting.menuOffset,
|
||||
appearanceSettings.themeMode,
|
||||
appearanceSettings.font,
|
||||
appearanceSettings.monospaceFont,
|
||||
appearanceSettings.layoutDirection,
|
||||
appearanceSettings.textDirection,
|
||||
appearanceSettings.locale,
|
||||
appearanceSettings.isMenuCollapsed,
|
||||
appearanceSettings.menuOffset,
|
||||
dateTimeSettings.dateFormat,
|
||||
dateTimeSettings.timeFormat,
|
||||
dateTimeSettings.timezoneId,
|
||||
@ -52,7 +59,7 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
/// Update selected theme in the user's settings and emit an updated state
|
||||
/// with the AppTheme named [themeName].
|
||||
Future<void> setTheme(String themeName) async {
|
||||
_setting.theme = themeName;
|
||||
_appearanceSettings.theme = themeName;
|
||||
_saveAppearanceSettings();
|
||||
emit(state.copyWith(appTheme: await AppTheme.fromName(themeName)));
|
||||
}
|
||||
@ -63,7 +70,7 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
|
||||
/// Update the theme mode in the user's settings and emit an updated state.
|
||||
void setThemeMode(ThemeMode themeMode) {
|
||||
_setting.themeMode = _themeModeToPB(themeMode);
|
||||
_appearanceSettings.themeMode = _themeModeToPB(themeMode);
|
||||
_saveAppearanceSettings();
|
||||
emit(state.copyWith(themeMode: themeMode));
|
||||
}
|
||||
@ -81,13 +88,13 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
}
|
||||
|
||||
void setLayoutDirection(LayoutDirection layoutDirection) {
|
||||
_setting.layoutDirection = layoutDirection.toLayoutDirectionPB();
|
||||
_appearanceSettings.layoutDirection = layoutDirection.toLayoutDirectionPB();
|
||||
_saveAppearanceSettings();
|
||||
emit(state.copyWith(layoutDirection: layoutDirection));
|
||||
}
|
||||
|
||||
void setTextDirection(AppFlowyTextDirection? textDirection) {
|
||||
_setting.textDirection =
|
||||
_appearanceSettings.textDirection =
|
||||
textDirection?.toTextDirectionPB() ?? TextDirectionPB.FALLBACK;
|
||||
_saveAppearanceSettings();
|
||||
emit(state.copyWith(textDirection: textDirection));
|
||||
@ -96,7 +103,7 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
/// Update selected font in the user's settings and emit an updated state
|
||||
/// with the font name.
|
||||
void setFontFamily(String fontFamilyName) {
|
||||
_setting.font = fontFamilyName;
|
||||
_appearanceSettings.font = fontFamilyName;
|
||||
_saveAppearanceSettings();
|
||||
emit(state.copyWith(font: fontFamilyName));
|
||||
}
|
||||
@ -118,8 +125,8 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
});
|
||||
|
||||
if (state.locale != newLocale) {
|
||||
_setting.locale.languageCode = newLocale.languageCode;
|
||||
_setting.locale.countryCode = newLocale.countryCode ?? "";
|
||||
_appearanceSettings.locale.languageCode = newLocale.languageCode;
|
||||
_appearanceSettings.locale.countryCode = newLocale.countryCode ?? "";
|
||||
_saveAppearanceSettings();
|
||||
emit(state.copyWith(locale: newLocale));
|
||||
}
|
||||
@ -127,13 +134,13 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
|
||||
// Saves the menus current visibility
|
||||
void saveIsMenuCollapsed(bool collapsed) {
|
||||
_setting.isMenuCollapsed = collapsed;
|
||||
_appearanceSettings.isMenuCollapsed = collapsed;
|
||||
_saveAppearanceSettings();
|
||||
}
|
||||
|
||||
// Saves the current resize offset of the menu
|
||||
void saveMenuOffset(double offset) {
|
||||
_setting.menuOffset = offset;
|
||||
_appearanceSettings.menuOffset = offset;
|
||||
_saveAppearanceSettings();
|
||||
}
|
||||
|
||||
@ -146,14 +153,14 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
_setting.settingKeyValue.remove(key);
|
||||
_appearanceSettings.settingKeyValue.remove(key);
|
||||
}
|
||||
|
||||
if (_setting.settingKeyValue[key] != value) {
|
||||
if (_appearanceSettings.settingKeyValue[key] != value) {
|
||||
if (value == null) {
|
||||
_setting.settingKeyValue.remove(key);
|
||||
_appearanceSettings.settingKeyValue.remove(key);
|
||||
} else {
|
||||
_setting.settingKeyValue[key] = value;
|
||||
_appearanceSettings.settingKeyValue[key] = value;
|
||||
}
|
||||
}
|
||||
_saveAppearanceSettings();
|
||||
@ -164,14 +171,14 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
Log.warn("The key should not be empty");
|
||||
return null;
|
||||
}
|
||||
return _setting.settingKeyValue[key];
|
||||
return _appearanceSettings.settingKeyValue[key];
|
||||
}
|
||||
|
||||
/// Called when the application launches.
|
||||
/// Uses the device locale when the application is opened for the first time.
|
||||
void readLocaleWhenAppLaunch(BuildContext context) {
|
||||
if (_setting.resetToDefault) {
|
||||
_setting.resetToDefault = false;
|
||||
if (_appearanceSettings.resetToDefault) {
|
||||
_appearanceSettings.resetToDefault = false;
|
||||
_saveAppearanceSettings();
|
||||
setLocale(context, context.deviceLocale);
|
||||
return;
|
||||
@ -204,7 +211,9 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
||||
}
|
||||
|
||||
Future<void> _saveAppearanceSettings() async {
|
||||
UserSettingsBackendService().setAppearanceSetting(_setting).then((result) {
|
||||
UserSettingsBackendService()
|
||||
.setAppearanceSetting(_appearanceSettings)
|
||||
.then((result) {
|
||||
result.fold(
|
||||
(l) => null,
|
||||
(error) => Log.error(error),
|
@ -0,0 +1,62 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/user/application/user_settings_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'notification_settings_cubit.freezed.dart';
|
||||
|
||||
class NotificationSettingsCubit extends Cubit<NotificationSettingsState> {
|
||||
final Completer<void> _initCompleter = Completer();
|
||||
|
||||
late final NotificationSettingsPB _notificationSettings;
|
||||
|
||||
NotificationSettingsCubit() : super(NotificationSettingsState.initial()) {
|
||||
UserSettingsBackendService()
|
||||
.getNotificationSettings()
|
||||
.then((notificationSettings) {
|
||||
_notificationSettings = notificationSettings;
|
||||
_initCompleter.complete();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> toggleNotificationsEnabled() async {
|
||||
await _initCompleter.future;
|
||||
|
||||
_notificationSettings.notificationsEnabled = !state.isNotificationsEnabled;
|
||||
_saveNotificationSettings();
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isNotificationsEnabled: _notificationSettings.notificationsEnabled,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _saveNotificationSettings() async {
|
||||
await _initCompleter.future;
|
||||
|
||||
UserSettingsBackendService()
|
||||
.setNotificationSettings(_notificationSettings)
|
||||
.then((result) {
|
||||
result.fold(
|
||||
(error) => Log.error(error),
|
||||
(r) => null,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class NotificationSettingsState with _$NotificationSettingsState {
|
||||
const NotificationSettingsState._();
|
||||
|
||||
const factory NotificationSettingsState({
|
||||
required bool isNotificationsEnabled,
|
||||
}) = _NotificationSettingsState;
|
||||
|
||||
factory NotificationSettingsState.initial() =>
|
||||
const NotificationSettingsState(isNotificationsEnabled: true);
|
||||
}
|
@ -13,6 +13,7 @@ enum SettingsPage {
|
||||
language,
|
||||
files,
|
||||
user,
|
||||
notifications,
|
||||
syncSetting,
|
||||
shortcuts,
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import 'package:appflowy/startup/plugin/plugin.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/home/home_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/home/home_service.dart';
|
||||
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'dart:io';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_notifications_view.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/sync_setting_view.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance_view.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_customize_shortcuts_view.dart';
|
||||
@ -101,6 +102,8 @@ class SettingsDialog extends StatelessWidget {
|
||||
didLogout: didLogout,
|
||||
didOpenUser: didOpenUser,
|
||||
);
|
||||
case SettingsPage.notifications:
|
||||
return const SettingsNotificationsView();
|
||||
case SettingsPage.syncSetting:
|
||||
return SyncSettingView(userId: user.id.toString());
|
||||
case SettingsPage.shortcuts:
|
||||
|
@ -2,7 +2,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/theme_setting_entry_template.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/theme_upload/theme_upload_view.dart';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/date_time.pbenum.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
|
@ -2,7 +2,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/util/google_font_family_extension.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/appearance_defaults.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/date_time.pbenum.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/create_file_setting.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/date_format_setting.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/time_format_setting.dart';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
|
@ -61,6 +61,13 @@ class SettingsMenu extends StatelessWidget {
|
||||
icon: Icons.account_box_outlined,
|
||||
changeSelectedPage: changeSelectedPage,
|
||||
),
|
||||
SettingsMenuElement(
|
||||
page: SettingsPage.notifications,
|
||||
selectedPage: currentPage,
|
||||
label: LocaleKeys.settings_menu_notifications.tr(),
|
||||
icon: Icons.notifications_outlined,
|
||||
changeSelectedPage: changeSelectedPage,
|
||||
),
|
||||
if (showSyncSetting)
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
|
@ -0,0 +1,45 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/settings/notifications/notification_settings_cubit.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/theme_setting_entry_template.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class SettingsNotificationsView extends StatelessWidget {
|
||||
const SettingsNotificationsView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<NotificationSettingsCubit, NotificationSettingsState>(
|
||||
builder: (context, state) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ThemeSettingEntryTemplateWidget(
|
||||
label: LocaleKeys
|
||||
.settings_notifications_enableNotifications_label
|
||||
.tr(),
|
||||
hint: LocaleKeys.settings_notifications_enableNotifications_hint
|
||||
.tr(),
|
||||
trailing: [
|
||||
Switch(
|
||||
value: state.isNotificationsEnabled,
|
||||
splashRadius: 0,
|
||||
activeColor: Theme.of(context).colorScheme.primary,
|
||||
onChanged: (value) {
|
||||
context
|
||||
.read<NotificationSettingsCubit>()
|
||||
.toggleNotificationsEnabled();
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import 'package:appflowy/user/application/user_settings_service.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:bloc_test/bloc_test.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
@ -18,6 +18,7 @@ void main() {
|
||||
group('$AppearanceSettingsCubit', () {
|
||||
late AppearanceSettingsPB appearanceSetting;
|
||||
late DateTimeSettingsPB dateTimeSettings;
|
||||
|
||||
setUp(() async {
|
||||
appearanceSetting =
|
||||
await UserSettingsBackendService().getAppearanceSetting();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/application/appearance.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_appearance/font_family_setting.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -241,6 +241,7 @@
|
||||
"language": "Language",
|
||||
"user": "User",
|
||||
"files": "Files",
|
||||
"notifications": "Notifications",
|
||||
"open": "Open Settings",
|
||||
"logout": "Logout",
|
||||
"logoutPrompt": "Are you sure to logout?",
|
||||
@ -256,6 +257,12 @@
|
||||
"historicalUserListTooltip": "This list displays your anonymous accounts. You can click on an account to view its details. Anonymous accounts are created by clicking the 'Get Started' button",
|
||||
"openHistoricalUser": "Click to open the anonymous account"
|
||||
},
|
||||
"notifications": {
|
||||
"enableNotifications": {
|
||||
"label": "Enable notifications",
|
||||
"hint": "Turn off to stop local notifications from appearing."
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
"resetSetting": "Reset this setting",
|
||||
"fontFamily": {
|
||||
|
@ -237,3 +237,17 @@ impl std::default::Default for DateTimeSettingsPB {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct NotificationSettingsPB {
|
||||
#[pb(index = 1)]
|
||||
pub notifications_enabled: bool,
|
||||
}
|
||||
|
||||
impl std::default::Default for NotificationSettingsPB {
|
||||
fn default() -> Self {
|
||||
NotificationSettingsPB {
|
||||
notifications_enabled: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ pub async fn get_date_time_settings(
|
||||
Ok(setting) => setting,
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"Deserialize AppearanceSettings failed: {:?}, fallback to default",
|
||||
"Deserialize DateTimeSettings failed: {:?}, fallback to default",
|
||||
e
|
||||
);
|
||||
DateTimeSettingsPB::default()
|
||||
@ -206,6 +206,42 @@ pub async fn get_date_time_settings(
|
||||
}
|
||||
}
|
||||
|
||||
const NOTIFICATION_SETTINGS_CACHE_KEY: &str = "notification_settings";
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub async fn set_notification_settings(
|
||||
store_preferences: AFPluginState<Weak<StorePreferences>>,
|
||||
data: AFPluginData<NotificationSettingsPB>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let store_preferences = upgrade_store_preferences(store_preferences)?;
|
||||
let setting = data.into_inner();
|
||||
store_preferences.set_object(NOTIFICATION_SETTINGS_CACHE_KEY, setting)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub async fn get_notification_settings(
|
||||
store_preferences: AFPluginState<Weak<StorePreferences>>,
|
||||
) -> DataResult<NotificationSettingsPB, FlowyError> {
|
||||
let store_preferences = upgrade_store_preferences(store_preferences)?;
|
||||
match store_preferences.get_str(NOTIFICATION_SETTINGS_CACHE_KEY) {
|
||||
None => data_result_ok(NotificationSettingsPB::default()),
|
||||
Some(s) => {
|
||||
let setting = match serde_json::from_str(&s) {
|
||||
Ok(setting) => setting,
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"Deserialize NotificationSettings failed: {:?}, fallback to default",
|
||||
e
|
||||
);
|
||||
NotificationSettingsPB::default()
|
||||
},
|
||||
};
|
||||
data_result_ok(setting)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub async fn get_user_setting(
|
||||
manager: AFPluginState<Weak<UserManager>>,
|
||||
|
@ -65,6 +65,14 @@ pub fn init(user_session: Weak<UserManager>) -> AFPlugin {
|
||||
.event(UserEvent::ResetWorkspace, reset_workspace_handler)
|
||||
.event(UserEvent::SetDateTimeSettings, set_date_time_settings)
|
||||
.event(UserEvent::GetDateTimeSettings, get_date_time_settings)
|
||||
.event(
|
||||
UserEvent::SetNotificationSettings,
|
||||
set_notification_settings,
|
||||
)
|
||||
.event(
|
||||
UserEvent::GetNotificationSettings,
|
||||
get_notification_settings,
|
||||
)
|
||||
}
|
||||
|
||||
pub struct SignUpContext {
|
||||
@ -317,4 +325,10 @@ pub enum UserEvent {
|
||||
/// Retrieve the Date/Time formats
|
||||
#[event(output = "DateTimeSettingsPB")]
|
||||
GetDateTimeSettings = 34,
|
||||
|
||||
#[event(input = "NotificationSettingsPB")]
|
||||
SetNotificationSettings = 35,
|
||||
|
||||
#[event(output = "NotificationSettingsPB")]
|
||||
GetNotificationSettings = 36,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user