diff --git a/lib/app.dart b/lib/app.dart index e0bf9f8d..e1607247 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -119,7 +119,7 @@ class _AppState extends ConsumerState with AfterLayoutMixin { ), child: MaterialApp( title: 'Material Notes', - home: NotesPage(), + home: NotesPage(label: null), navigatorKey: rootNavigatorKey, builder: (context, child) { // Change the widget shown when a widget building fails diff --git a/lib/common/actions/notes/add.dart b/lib/common/actions/notes/add.dart index af829523..2b29cbc3 100644 --- a/lib/common/actions/notes/add.dart +++ b/lib/common/actions/notes/add.dart @@ -10,12 +10,20 @@ import 'select.dart'; /// Adds a note. /// /// A [content] can be specified when the note is created from a sharing intent. -Future addNote(BuildContext context, WidgetRef ref, {String? content}) async { +Future addNote(BuildContext context, WidgetRef ref, {String? content}) async { if (isNotesSelectionModeNotifier.value) { exitNotesSelectionMode(context, ref); } - final note = content == null ? RichTextNote.empty() : RichTextNote.content(content); + final Note note; + switch (NoteType) { + case == PlainTextNote: + note = content == null ? PlainTextNote.empty() : PlainTextNote.content(content); + case == RichTextNote: + note = content == null ? RichTextNote.empty() : RichTextNote.content(content); + default: + throw Exception('Unknown note type when creating a new note: $NoteType'); + } // If some content was provided, immediately save the note without waiting for changes in the editor if (content != null) { diff --git a/lib/common/constants/constants.dart b/lib/common/constants/constants.dart index 34b79c74..f824a347 100644 --- a/lib/common/constants/constants.dart +++ b/lib/common/constants/constants.dart @@ -1,9 +1,14 @@ import 'package:flutter/material.dart'; -import '../logs/app_logger.dart'; -import '../../l10n/app_localizations/app_localizations.g.dart'; import 'package:parchment/codecs.dart'; import 'package:saf_stream/saf_stream.dart'; import 'package:saf_util/saf_util.dart'; +import 'package:uuid/uuid.dart'; + +import '../../l10n/app_localizations/app_localizations.g.dart'; +import '../logs/app_logger.dart'; + +/// An UUID generator. +final uuid = Uuid(); /// Contact email address. const contactEmail = 'contact@maelchiotti.dev'; diff --git a/lib/common/navigation/app_bars/basic_app_bar.dart b/lib/common/navigation/app_bars/basic_app_bar.dart index 1731bde8..5a0b99c2 100644 --- a/lib/common/navigation/app_bars/basic_app_bar.dart +++ b/lib/common/navigation/app_bars/basic_app_bar.dart @@ -1,24 +1,16 @@ import 'package:flutter/material.dart'; /// Basic app bar. -/// -/// Contains: -/// - A back button if built with [BasicAppBar.back]. -/// - The title of the current route. class BasicAppBar extends StatelessWidget { - /// Default constructor. + /// A basic app bar with a title. const BasicAppBar({ super.key, required this.title, - this.back = false, }); /// Title to display in the app bar. final String title; - /// Whether to show the back button. - final bool back; - @override Widget build(BuildContext context) { return AppBar( diff --git a/lib/common/navigation/app_bars/editor_app_bar.dart b/lib/common/navigation/app_bars/editor_app_bar.dart index e5971b8d..046dfd63 100644 --- a/lib/common/navigation/app_bars/editor_app_bar.dart +++ b/lib/common/navigation/app_bars/editor_app_bar.dart @@ -2,6 +2,7 @@ import 'package:fleather/fleather.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../../../models/note/notes_types.dart'; import '../../../pages/editor/sheets/about_sheet.dart'; import '../../../providers/notifiers/notifiers.dart'; import '../../actions/notes/copy.dart'; @@ -16,16 +17,9 @@ import '../../preferences/preference_key.dart'; import '../enums/bin_menu_option.dart'; import '../enums/note_menu_option.dart'; -/// Editor's app bar. -/// -/// Contains: -/// - A back button. -/// - The title of the editor route. -/// - The undo/redo buttons if enabled by the user. -/// - The checklist button if enabled by the user. -/// - The menu with further actions. +/// Editor app bar. class EditorAppBar extends ConsumerStatefulWidget { - /// Default constructor. + /// App bar of the editor page allowing to perform actions on the note. const EditorAppBar({ super.key, }); @@ -35,12 +29,10 @@ class EditorAppBar extends ConsumerStatefulWidget { } class _BackAppBarState extends ConsumerState { - /// Switches the editor mode between editing and viewing. void switchMode() { - isFleatherEditorEditMode.value = !isFleatherEditorEditMode.value; + isEditorInEditModeNotifier.value = !isEditorInEditModeNotifier.value; } - /// Performs the action associated with the selected [menuOption] on the not deleted note. Future onNoteMenuOptionSelected(NoteMenuOption menuOption) async { // Manually close the keyboard FocusManager.instance.primaryFocus?.unfocus(); @@ -74,7 +66,6 @@ class _BackAppBarState extends ConsumerState { } } - /// Performs the action associated with the selected [menuOption] on the deleted note. Future onBinMenuOptionSelected(BinMenuOption menuOption) async { // Manually close the keyboard FocusManager.instance.primaryFocus?.unfocus(); @@ -102,7 +93,6 @@ class _BackAppBarState extends ConsumerState { } } - /// Undoes the latest change in the editor. void undo() { final editorController = fleatherControllerNotifier.value; @@ -113,7 +103,6 @@ class _BackAppBarState extends ConsumerState { editorController.undo(); } - /// Redoes the latest change in the editor. void redo() { final editorController = fleatherControllerNotifier.value; @@ -124,7 +113,6 @@ class _BackAppBarState extends ConsumerState { editorController.redo(); } - /// Toggles the presence of the checklist in the currently active line of the editor. void toggleChecklist() { final editorController = fleatherControllerNotifier.value; @@ -144,50 +132,45 @@ class _BackAppBarState extends ConsumerState { final editorController = fleatherControllerNotifier.value; final showEditorModeButton = PreferenceKey.editorModeButton.getPreferenceOrDefault(); - final showUndoRedoButtons = PreferenceKey.showUndoRedoButtons.getPreferenceOrDefault(); - final showChecklistButton = PreferenceKey.showChecklistButton.getPreferenceOrDefault(); final enableLabels = PreferenceKey.enableLabels.getPreferenceOrDefault(); return ValueListenableBuilder( - valueListenable: fleatherFieldHasFocusNotifier, - builder: (context, hasFocus, child) => ValueListenableBuilder( - valueListenable: isFleatherEditorEditMode, + valueListenable: editorHasFocusNotifier, + builder: (context, editorHasFocus, child) => ValueListenableBuilder( + valueListenable: isEditorInEditModeNotifier, builder: (context, isEditMode, child) => AppBar( leading: BackButton(), actions: note == null ? null : [ if (!note.deleted) ...[ - if (showUndoRedoButtons) + if (note.type == NoteType.richText) ...[ ValueListenableBuilder( valueListenable: fleatherControllerCanUndoNotifier, builder: (context, canUndo, child) => IconButton( icon: const Icon(Icons.undo), tooltip: l.tooltip_undo, - onPressed: - hasFocus && canUndo && editorController != null && editorController.canUndo && isEditMode - ? undo - : null, + onPressed: editorHasFocus && + canUndo && + editorController != null && + editorController.canUndo && + isEditMode + ? undo + : null, ), ), - if (showUndoRedoButtons) ValueListenableBuilder( valueListenable: fleatherControllerCanRedoNotifier, builder: (context, canRedo, child) => IconButton( icon: const Icon(Icons.redo), tooltip: l.tooltip_redo, - onPressed: hasFocus && canRedo && isEditMode ? redo : null, + onPressed: editorHasFocus && canRedo && isEditMode ? redo : null, ), ), - if (showChecklistButton) - IconButton( - icon: const Icon(Icons.checklist), - tooltip: l.tooltip_toggle_checkbox, - onPressed: hasFocus && isEditMode ? toggleChecklist : null, - ), + ], if (showEditorModeButton) ValueListenableBuilder( - valueListenable: isFleatherEditorEditMode, + valueListenable: isEditorInEditModeNotifier, builder: (context, isEditMode, child) => IconButton( icon: Icon(isEditMode ? Icons.visibility : Icons.edit), tooltip: isEditMode diff --git a/lib/common/navigation/app_bars/notes_app_bar.dart b/lib/common/navigation/app_bars/notes_app_bar.dart index 9f037944..a07f761e 100644 --- a/lib/common/navigation/app_bars/notes_app_bar.dart +++ b/lib/common/navigation/app_bars/notes_app_bar.dart @@ -2,6 +2,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../../../models/label/label.dart'; import '../../../models/note/note.dart'; import '../../../providers/bin/bin_provider.dart'; import '../../../providers/notes/notes_provider.dart'; @@ -29,16 +30,20 @@ class NotesAppBar extends ConsumerWidget { /// Default constructor. const NotesAppBar({ super.key, + this.label, this.notesPage = true, }); + /// The label used to filter the notes. + final Label? label; + /// Whether the current page is the notes list. final bool notesPage; /// Returns the title of the app bar. String get title { if (notesPage) { - return currentLabelFilter?.name ?? l.navigation_notes; + return label?.name ?? l.navigation_notes; } else { return l.navigation_bin; } diff --git a/lib/common/navigation/app_bars/notes_selection_app_bar.dart b/lib/common/navigation/app_bars/notes_selection_app_bar.dart index 1dea8abe..5fbedbdd 100644 --- a/lib/common/navigation/app_bars/notes_selection_app_bar.dart +++ b/lib/common/navigation/app_bars/notes_selection_app_bar.dart @@ -102,25 +102,27 @@ class NotesSelectionAppBar extends ConsumerWidget { } @override - Widget build(BuildContext context, WidgetRef ref) => notesPage - ? ref.watch(notesProvider(label: currentLabelFilter)).when( - data: (notes) => buildAppBar( - context, - ref, - notes.where((note) => note.selected).toList(), - notes.length, - ), - error: (exception, stackTrace) => ErrorPlaceholder(exception: exception, stackTrace: stackTrace), - loading: () => const LoadingPlaceholder(), - ) - : ref.watch(binProvider).when( - data: (notes) => buildAppBar( - context, - ref, - notes.where((note) => note.selected).toList(), - notes.length, - ), - error: (exception, stackTrace) => ErrorPlaceholder(exception: exception, stackTrace: stackTrace), - loading: () => const LoadingPlaceholder(), - ); + Widget build(BuildContext context, WidgetRef ref) { + return notesPage + ? ref.watch(notesProvider(label: currentLabelFilter)).when( + data: (notes) => buildAppBar( + context, + ref, + notes.where((note) => note.selected).toList(), + notes.length, + ), + error: (exception, stackTrace) => ErrorPlaceholder(exception: exception, stackTrace: stackTrace), + loading: () => const LoadingPlaceholder(), + ) + : ref.watch(binProvider).when( + data: (notes) => buildAppBar( + context, + ref, + notes.where((note) => note.selected).toList(), + notes.length, + ), + error: (exception, stackTrace) => ErrorPlaceholder(exception: exception, stackTrace: stackTrace), + loading: () => const LoadingPlaceholder(), + ); + } } diff --git a/lib/common/navigation/side_navigation.dart b/lib/common/navigation/side_navigation.dart index 2c2daf88..b93695c8 100644 --- a/lib/common/navigation/side_navigation.dart +++ b/lib/common/navigation/side_navigation.dart @@ -124,12 +124,12 @@ class _SideNavigationState extends ConsumerState { ? NavigatorUtils.push( context, '${NavigationRoute.label.name}-${label.name}', - NotesPage(), + NotesPage(label: currentLabelFilter), ) : NavigatorUtils.go( context, '${NavigationRoute.label.name}-${label.name}', - NotesPage(), + NotesPage(label: currentLabelFilter), ); } else if (index == labels.length + 1) { NavigationRoute.manageLabels.pushOrGo(context, isHomeRoute(route), LabelsPage()); diff --git a/lib/common/preferences/preference_key.dart b/lib/common/preferences/preference_key.dart index d82e8294..d50a7e3e 100644 --- a/lib/common/preferences/preference_key.dart +++ b/lib/common/preferences/preference_key.dart @@ -3,7 +3,7 @@ import 'preferences_utils.dart'; // ignore_for_file: public_member_api_docs /// Keys of preferences. -enum PreferenceKey { +enum PreferenceKey { // Appearance locale('en', backup: false), theme('system'), @@ -11,8 +11,18 @@ enum PreferenceKey { blackTheming(false), appFont('systemDefault'), editorFont('systemDefault'), + + // Notes types + availableNotesTypes>(['plainText', 'richText']), + defaultShortcutNoteType('plainText'), + + // Rich text notes + useParagraphsSpacing(true), + + // Notes tiles showTilesBackground(false), showSeparators(false), + showNoteTypeIcon(true), showTitlesOnly(false), showTitlesOnlyDisableInSearchView(true), maximumContentPreviewLines(3), @@ -26,13 +36,9 @@ enum PreferenceKey { binSwipeLeftAction('restore'), // Editor - showUndoRedoButtons(true), - showChecklistButton(true), - showToolbar(true), editorModeButton(true), openEditorReadingMode(false), focusTitleOnNewNote(false), - useParagraphsSpacing(true), // Labels enableLabels(true), diff --git a/lib/common/preferences/preferences_utils.dart b/lib/common/preferences/preferences_utils.dart index 29ad5d39..5e61c7e3 100644 --- a/lib/common/preferences/preferences_utils.dart +++ b/lib/common/preferences/preferences_utils.dart @@ -1,7 +1,8 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + import '../constants/constants.dart'; import 'preference_key.dart'; -import 'package:shared_preferences/shared_preferences.dart'; /// Manages user preferences. class PreferencesUtils { @@ -36,16 +37,19 @@ class PreferencesUtils { return; } - if (T == bool) { - await _preferences.setBool(preferenceKey.name, value as bool); - } else if (T == int) { - await _preferences.setInt(preferenceKey.name, value as int); - } else if (T == double) { - await _preferences.setDouble(preferenceKey.name, value as double); - } else if (T == String) { - await _preferences.setString(preferenceKey.name, value as String); - } else if (T == List) { - await _preferences.setStringList(preferenceKey.name, value as List); + switch (T) { + case == bool: + await _preferences.setBool(preferenceKey.name, value as bool); + case == int: + await _preferences.setInt(preferenceKey.name, value as int); + case == double: + await _preferences.setDouble(preferenceKey.name, value as double); + case == String: + await _preferences.setString(preferenceKey.name, value as String); + case == List: + await _preferences.setStringList(preferenceKey.name, value as List); + default: + throw ArgumentError('Invalid preference type: $T'); } } @@ -58,7 +62,17 @@ class PreferencesUtils { } try { - return _preferences.get(preferenceKey.name) as T?; + if (T == List) { + return _preferences.getStringList(preferenceKey.name) as T?; + } + + return switch (T) { + == bool => _preferences.getBool(preferenceKey.name), + == int => _preferences.getInt(preferenceKey.name), + == double => _preferences.getDouble(preferenceKey.name), + == String => _preferences.getString(preferenceKey.name), + _ => throw ArgumentError('Invalid preference type: $T'), + } as T?; } // On type conversion error, reset the preference to its default value on TypeError catch (error) { diff --git a/lib/common/preferences/watched_preferences.dart b/lib/common/preferences/watched_preferences.dart index c38cdcf0..bc8f196c 100644 --- a/lib/common/preferences/watched_preferences.dart +++ b/lib/common/preferences/watched_preferences.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import '../../models/note/notes_types.dart'; import '../ui/theme_utils.dart'; import 'enums/bin_swipe_action.dart'; import 'enums/font.dart'; @@ -16,9 +17,15 @@ class WatchedPreferences { late bool dynamicTheming; late bool blackTheming; late Font appFont; - late bool showTitlesOnly; + + // Notes types + late List availableNotesTypes; + + // Notes tiles late bool showTilesBackground; late bool showSeparators; + late bool showNoteTypeIcon; + late bool showTitlesOnly; late int maximumContentPreviewLines; // Behavior @@ -41,8 +48,10 @@ class WatchedPreferences { bool? dynamicTheming, bool? blackTheming, Font? appFont, + List? availableNotesTypes, bool? showTitlesOnly, bool? showTilesBackground, + bool? showNoteTypeIcon, bool? showSeparators, int? maximumContentPreviewLines, SwipeAction? rightSwipeAction, @@ -59,8 +68,12 @@ class WatchedPreferences { this.dynamicTheming = dynamicTheming ?? PreferenceKey.dynamicTheming.getPreferenceOrDefault(); this.blackTheming = blackTheming ?? PreferenceKey.blackTheming.getPreferenceOrDefault(); this.appFont = appFont ?? Font.appFromPreference(); + + this.availableNotesTypes = availableNotesTypes ?? NoteType.availableTypes; + this.showTitlesOnly = showTitlesOnly ?? PreferenceKey.showTitlesOnly.getPreferenceOrDefault(); this.showTilesBackground = showTilesBackground ?? PreferenceKey.showTilesBackground.getPreferenceOrDefault(); + this.showNoteTypeIcon = showNoteTypeIcon ?? PreferenceKey.showNoteTypeIcon.getPreferenceOrDefault(); this.showSeparators = showSeparators ?? PreferenceKey.showSeparators.getPreferenceOrDefault(); this.maximumContentPreviewLines = maximumContentPreviewLines ?? PreferenceKey.maximumContentPreviewLines.getPreferenceOrDefault(); diff --git a/lib/common/system/quick_actions_utils.dart b/lib/common/system/quick_actions_utils.dart index c79b0b2a..b9fd8ced 100644 --- a/lib/common/system/quick_actions_utils.dart +++ b/lib/common/system/quick_actions_utils.dart @@ -2,6 +2,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:quick_actions/quick_actions.dart'; +import '../../models/note/note.dart'; +import '../../models/note/notes_types.dart'; import '../actions/notes/add.dart'; import '../localization/localizations_utils.dart'; @@ -16,7 +18,14 @@ class QuickActionsUtils { quickActions.initialize((action) { if (action == 'add_note') { - addNote(context, ref); + final defaultShortcutNoteType = NoteType.defaultShortcutType; + + switch (defaultShortcutNoteType) { + case NoteType.plainText: + addNote(context, ref); + case NoteType.richText: + addNote(context, ref); + } } }); diff --git a/lib/common/system/share_utils.dart b/lib/common/system/share_utils.dart index 3daedc7b..e58a7960 100644 --- a/lib/common/system/share_utils.dart +++ b/lib/common/system/share_utils.dart @@ -5,6 +5,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:parchment_delta/parchment_delta.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; +import '../../models/note/note.dart'; +import '../../models/note/notes_types.dart'; import '../actions/notes/add.dart'; import '../constants/constants.dart'; @@ -38,5 +40,14 @@ void _processSharedData(WidgetRef ref, List data) { delta.insert('$line\n'); } - addNote(rootNavigatorKey.currentContext!, ref, content: jsonEncode(delta)); + final defaultShortcutNoteType = NoteType.defaultShortcutType; + final context = rootNavigatorKey.currentContext!; + final content = jsonEncode(delta); + + switch (defaultShortcutNoteType) { + case NoteType.plainText: + addNote(context, ref, content: content); + case NoteType.richText: + addNote(context, ref, content: content); + } } diff --git a/lib/common/widgets/notes/note_tile.dart b/lib/common/widgets/notes/note_tile.dart index c23cd66a..bb7ef2b5 100644 --- a/lib/common/widgets/notes/note_tile.dart +++ b/lib/common/widgets/notes/note_tile.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:gap/gap.dart'; import '../../../models/note/note.dart'; import '../../../navigation/navigator_utils.dart'; @@ -150,6 +151,7 @@ class _NoteTileState extends ConsumerState { Widget build(BuildContext context) { final showTitlesOnly = ref.watch(preferencesProvider.select((preferences) => preferences.showTitlesOnly)); final showTilesBackground = ref.watch(preferencesProvider.select((preferences) => preferences.showTilesBackground)); + final showNoteTypeIcon = ref.watch(preferencesProvider.select((preferences) => preferences.showNoteTypeIcon)); final showTitlesOnlyDisableInSearchView = PreferenceKey.showTitlesOnlyDisableInSearchView.getPreferenceOrDefault(); final disableSubduedNoteContentPreview = ref.watch(preferencesProvider.select((preferences) => preferences.disableSubduedNoteContentPreview)); @@ -215,14 +217,25 @@ class _NoteTileState extends ConsumerState { ], ), ), + Column( + children: [ + if (widget.note.pinned && !widget.note.deleted) ...[ + Padding(padding: Paddings.horizontal(2.0)), + Icon( + Icons.push_pin, + size: Sizes.pinIconSize.size, + ), + ], + if (showNoteTypeIcon) ...[ + Gap(8.0), + Icon( + widget.note.type.icon, + size: Sizes.pinIconSize.size, + ), + ], + ], + ), // Trailing - if (widget.note.pinned && !widget.note.deleted) ...[ - Padding(padding: Paddings.horizontal(2.0)), - Icon( - Icons.push_pin, - size: Sizes.pinIconSize.size, - ), - ], ], ), if (enableLabels && showLabelsListOnNoteTile) ...[ diff --git a/lib/common/widgets/notes/notes_list.dart b/lib/common/widgets/notes/notes_list.dart index 9a51b480..7e27c48c 100644 --- a/lib/common/widgets/notes/notes_list.dart +++ b/lib/common/widgets/notes/notes_list.dart @@ -6,7 +6,6 @@ import '../../../models/label/label.dart'; import '../../../models/note/note.dart'; import '../../../providers/bin/bin_provider.dart'; import '../../../providers/notes/notes_provider.dart'; -import '../../../providers/notifiers/notifiers.dart'; import '../../../providers/preferences/preferences_provider.dart'; import '../../constants/paddings.dart'; import '../../constants/separators.dart'; @@ -83,9 +82,7 @@ class NotesList extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return notesPage ? ref.watch(notesProvider(label: label)).when( - data: (notes) { - return child(context, ref, notes); - }, + data: (notes) => child(context, ref, notes), error: (exception, stackTrace) => ErrorPlaceholder(exception: exception, stackTrace: stackTrace), loading: () => const LoadingPlaceholder(), ) diff --git a/lib/l10n/translations/app_en.arb b/lib/l10n/translations/app_en.arb index da04172a..ccb56a3d 100644 --- a/lib/l10n/translations/app_en.arb +++ b/lib/l10n/translations/app_en.arb @@ -77,6 +77,10 @@ "@navigation_settings_appearance": { "description": "Title of the settings page regarding the application's appearance." }, + "navigation_settings_notes_types": "Notes types", + "@navigation_settings_notes_types": { + "description": "Title of the settings page regarding the notes types." + }, "navigation_settings_notes_tiles": "Notes tiles", "@navigation_settings_notes_tiles": { "description": "Title of the settings page regarding the notes tiles appearance." @@ -217,6 +221,14 @@ "@settings_show_separators_description": { "description": "Description of the setting tile to show the separators between the notes tiles." }, + "settings_show_note_type_icon": "Show type icon", + "@settings_show_note_type_icon": { + "description": "Title of the setting tile to show the icon of the type of the note." + }, + "settings_show_note_type_icon_description": "Show the icon of the type of the note", + "@settings_show_note_type_icon_description": { + "description": "Description of the setting tile to show the icon of the type of the note." + }, "settings_show_titles_only": "Titles only", "@settings_show_titles_only": { "description": "Title of the setting tile to only show the titles of the notes in the notes tiles." @@ -313,41 +325,53 @@ "@settings_bin_swipe_action_left_description": { "description": "Description of the setting tile to choose which action to trigger when a left swipe is performed on a note tile in the bin." }, - "settings_editor": "Editor", - "@settings_editor": { - "description": "Title of the settings page regarding the notes content editor." + "settings_page_notes_types": "Notes types", + "@settings_page_notes_types": { + "description": "Title of the settings page regarding the notes types." }, - "settings_editor_description": "Buttons, toolbar, reading mode, spacing", - "@settings_editor_description": { - "description": "Description of the editor settings page." + "settings_page_notes_types_description": "Types to use, per-type settings", + "@settings_page_notes_types_description": { + "description": "Description of the settings page regarding the notes types." + }, + "settings_section_types_to_use": "Types to use", + "@settings_section_types_to_use": { + "description": "Title of the settings section regarding the notes types to use." }, - "settings_editor_formatting": "Formatting", - "@settings_editor_formatting": { - "description": "Title of the settings section regarding the notes content formatting in the editor." + "settings_section_per_type_settings": "Per-type settings", + "@settings_section_per_type_settings": { + "description": "Title of the settings section regarding the per-type settings." }, - "settings_show_undo_redo_buttons": "Undo/redo buttons", - "@settings_show_undo_redo_buttons": { - "description": "Title of the setting tile to enable the the undo and redo buttons in the editor." + "settings_available_notes_types": "Available notes types", + "@settings_available_notes_types": { + "description": "Title of the setting tile to choose the available notes types." }, - "settings_show_undo_redo_buttons_description": "Show the buttons to undo and redo changes in the editor''s app bar", - "@settings_show_undo_redo_buttons_description": { - "description": "Description of the setting tile to enable the the undo and redo buttons in the editor." + "settings_available_notes_types_description": "The list of notes types that can be created with the \"Add\" button from the notes page. When removing a type, already existing notes with that type are not deleted and can still be used normally", + "@settings_available_notes_types_description": { + "description": "Description of the setting tile to choose the available notes types." }, - "settings_show_checklist_button": "Checklist button", - "@settings_show_checklist_button": { - "description": "Title of the setting tile to enable the checklist button in the editor." + "settings_available_default_shortcut_type": "Default shortcut type", + "@settings_available_default_shortcut_type": { + "description": "Title of the setting tile to choose the default note type to use when creating a note from a shortcut." }, - "settings_show_checklist_button_description": "Show the button to toggle checklists in the editor''s app bar, hiding it from the editor''s toolbar if enabled", - "@settings_show_checklist_button_description": { - "description": "Description of the setting tile to enable the checklist button in the editor." + "settings_available_default_shortcut_type_description": "The default note type to use when creating a note from a shortcut. It can be a type that is not available from the \"Add\" button", + "@settings_available_default_shortcut_type_description": { + "description": "Description of the setting tile to choose the default note type to use when creating a note from a shortcut." }, - "settings_show_toolbar": "Toolbar", - "@settings_show_toolbar": { - "description": "Title of the setting tile to enable the toolbar for advanced formatting options in the editor." + "settings_page_rich_text_notes_description": "Appearance", + "@settings_page_rich_text_notes_description": { + "description": "Description of the settings page regarding the rich text notes." }, - "settings_show_toolbar_description": "Show the editor''s toolbar to enable advanced text formatting", - "@settings_show_toolbar_description": { - "description": "Description of the setting tile to enable the toolbar for advanced formatting options in the editor." + "settings_section_rich_text_notes_appearance": "Appearance", + "@settings_section_rich_text_notes_appearance": { + "description": "Description of the settings page regarding the rich text notes." + }, + "settings_editor": "Editor", + "@settings_editor": { + "description": "Title of the settings page regarding the notes content editor." + }, + "settings_editor_description": "Behavior", + "@settings_editor_description": { + "description": "Description of the editor settings page." }, "settings_editor_behavior": "Behavior", "@settings_editor_behavior": { @@ -699,6 +723,14 @@ "@tooltip_fab_add_note": { "description": "Floating action button in the notes page to add a new note." }, + "tooltip_fab_add_plain_text_note": "Add a plain text note", + "@tooltip_fab_add_plain_text_note": { + "description": "Floating action button in the notes page to add a new plain text note." + }, + "tooltip_fab_add_rich_text_note": "Add a rich text note", + "@tooltip_fab_add_rich_text_note": { + "description": "Floating action button in the notes page to add a new rich text note." + }, "tooltip_fab_add_label": "Add a label", "@tooltip_fab_add_label": { "description": "Floating action button in the labels page to add a new label." diff --git a/lib/l10n/translations/app_zh-TW.arb b/lib/l10n/translations/app_zh-TW.arb new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/lib/l10n/translations/app_zh-TW.arb @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/lib/models/note/index/note_index.dart b/lib/models/note/index/note_index.dart index abb6b778..523a1857 100644 --- a/lib/models/note/index/note_index.dart +++ b/lib/models/note/index/note_index.dart @@ -1,4 +1,5 @@ import 'package:json_annotation/json_annotation.dart'; + import '../note.dart'; part 'note_index.g.dart'; @@ -7,7 +8,7 @@ part 'note_index.g.dart'; @JsonSerializable() class NoteIndex { /// The ID of the note. - final int id; + final String id; /// Whether the note is deleted. final bool deleted; diff --git a/lib/models/note/note.dart b/lib/models/note/note.dart index c2247224..5340169b 100644 --- a/lib/models/note/note.dart +++ b/lib/models/note/note.dart @@ -10,9 +10,12 @@ import '../../common/files/encryption_utils.dart'; import '../../common/preferences/enums/sort_method.dart'; import '../../common/preferences/preference_key.dart'; import '../label/label.dart'; +import 'notes_types.dart'; part 'note.g.dart'; +part 'plain_text/plain_text_note.dart'; + part 'rich_text/rich_text_note.dart'; /// Converts the [labels] to a JSON-compatible list of strings. @@ -20,11 +23,15 @@ List labelToJson(IsarLinks