diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..62da7831 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,10 @@ +# Contributing + +## Localization + +In order to improve or add support for a language, please follow these steps: + +- Localized strings can be found in two different places: + - The `app_XX.arb` file located in [`lib/l10n`](lib/l10n) (where `XX` corresponds to the language code), that contains the vast majority of all strings. Please make sure that you do not localize any parameter name (ex: `{parameter}`) and that you do escape single quotes (ex: `I''m ok` instead of `I'm ok`). + - The [`hardcoded_localizations.dart`](lib/l10n/hardcoded_localizations.dart), that contains a few specific strings that need to be hardcoded. +- Localized strings can be generated with the `flutter gen-l10n` command. Check that the [`unstranslated.txt`](lib/l10n/untranslated.txt) file is empty, otherwise it will indicate which strings you did not translate. diff --git a/README.md b/README.md index 9f84cee9..b3cbe834 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ [![Releases](https://img.shields.io/github/v/release/maelchiotti/LocalMaterialNotes)](https://github.com/maelchiotti/LocalMaterialNotes/releases) [![Issues](https://img.shields.io/github/issues/maelchiotti/LocalMaterialNotes)](https://github.com/maelchiotti/LocalMaterialNotes/issues) +[Get it on Google Play](https://play.google.com/store/apps/details?id=com.maelchiotti.localmaterialnotes) +[Get it on GitHub](https://github.com/maelchiotti/LocalMaterialNotes/releases/latest) + # Local Material Notes @@ -21,10 +24,10 @@ Simple, local, material design notes.
- Screenshot of the notes list - Screenshots of the note editor - Screenshot of the bin - Screenshot of the settings + Screenshot of the notes list in selection mode + Screenshots of the search feature + Screenshot of the notes list in the dark mode with dynamic theming + Screenshot of the notes list in the light mode with dynamic theming
## Features @@ -65,16 +68,25 @@ See more screenshots [here](assets/screenshots). ## Supported languages -- English: 100% -- French: 100% - -## Alternatives +- English +- French +- Turkish -- [Simplenote](https://simplenote.com) for simple text notes that are synchronized over your devices and available on several platforms. Also provides extra features such as tags, history and collaboration. +To improve or add support for a language, please see [CONTRIBUTING.md](CONTRIBUTING.md#localization). ## Credits - [Material Design Icons](https://github.com/google/material-design-icons) for the [notes](https://fonts.google.com/icons?selected=Material+Symbols+Outlined:notes) icon used for the logo. +- [Material Files](https://github.com/zhanghai/MaterialFiles) for the general design inspiration, and especially the logo and its color. +- [Simplenote](https://simplenote.com) for the general layout of the app and its basic features. + +### Localization + +- Turkish: [xe1st](https://github.com/xe1st). + +## Contributing + +Please see [CONTRIBUTING.md](CONTRIBUTING.md). --- diff --git a/analysis_options.yaml b/analysis_options.yaml index dc072a0f..9f3ba910 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -4,4 +4,9 @@ analyzer: exclude: - '**.g.dart' plugins: - - custom_lint \ No newline at end of file + - custom_lint + +linter: + rules: + - always_put_control_body_on_new_line + - curly_braces_in_flow_control_structures \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4b574f77..71f95195 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ + android:icon="@mipmap/ic_launcher"> + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..fb3f1ad7 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..24f9b0b1 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..6dc25c74 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..c13528ca Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..1900900a Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..b13ef639 --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #2278e9 + \ No newline at end of file diff --git a/assets/github/social_preview.png b/assets/github/social_preview.png new file mode 100644 index 00000000..11a7b776 Binary files /dev/null and b/assets/github/social_preview.png differ diff --git a/assets/github/social_preview.psd b/assets/github/social_preview.psd new file mode 100644 index 00000000..1ea22712 Binary files /dev/null and b/assets/github/social_preview.psd differ diff --git a/assets/icons/icon_android_12.png b/assets/icons/icon_android_12.png deleted file mode 100644 index 9bdebca2..00000000 Binary files a/assets/icons/icon_android_12.png and /dev/null differ diff --git a/assets/icons/icon_foreground.png b/assets/icons/icon_foreground.png new file mode 100644 index 00000000..fcccc644 Binary files /dev/null and b/assets/icons/icon_foreground.png differ diff --git a/assets/icons/icon_foreground.svg b/assets/icons/icon_foreground.svg new file mode 100644 index 00000000..0f494fa7 --- /dev/null +++ b/assets/icons/icon_foreground.svg @@ -0,0 +1,17 @@ + + + + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/assets/icons/icon_foreground_monochrome.png b/assets/icons/icon_foreground_monochrome.png new file mode 100644 index 00000000..04b58699 Binary files /dev/null and b/assets/icons/icon_foreground_monochrome.png differ diff --git a/assets/icons/icon_full.png b/assets/icons/icon_full.png deleted file mode 100644 index 21abd00f..00000000 Binary files a/assets/icons/icon_full.png and /dev/null differ diff --git a/assets/icons/icon_full.svg b/assets/icons/icon_full.svg deleted file mode 100644 index 60b2e191..00000000 --- a/assets/icons/icon_full.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - diff --git a/assets/play_store/banner.png b/assets/play_store/banner.png index 1d5b93e2..1a9219e8 100644 Binary files a/assets/play_store/banner.png and b/assets/play_store/banner.png differ diff --git a/assets/play_store/banner.psd b/assets/play_store/banner.psd index 81d4558a..3e7701e9 100644 Binary files a/assets/play_store/banner.psd and b/assets/play_store/banner.psd differ diff --git a/flutter_launcher_icons.yaml b/flutter_launcher_icons.yaml index 6dc2d2bf..cf7caa05 100644 --- a/flutter_launcher_icons.yaml +++ b/flutter_launcher_icons.yaml @@ -1,6 +1,9 @@ # dart run flutter_launcher_icons flutter_launcher_icons: - image_path: "assets/logos/icon.png" - android: "launcher_icon" - min_sdk_android: 34 + image_path: "assets/icons/icon.png" + adaptive_icon_foreground: "assets/icons/icon_foreground.png" + adaptive_icon_monochrome: "assets/icons/icon_foreground_monochrome.png" + adaptive_icon_background: "#2278e9" + android: true + min_sdk_android: 21 ios: false \ No newline at end of file diff --git a/lib/app.dart b/lib/app.dart index 1a5f6760..cc9e1902 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:after_layout/after_layout.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -7,6 +8,7 @@ import 'package:localmaterialnotes/common/routing/router.dart'; import 'package:localmaterialnotes/l10n/app_localizations.g.dart'; import 'package:localmaterialnotes/utils/constants/constants.dart'; import 'package:localmaterialnotes/utils/locale_manager.dart'; +import 'package:localmaterialnotes/utils/quick_actions_manager.dart'; import 'package:localmaterialnotes/utils/share_manager.dart'; import 'package:localmaterialnotes/utils/theme_manager.dart'; @@ -15,7 +17,7 @@ class App extends ConsumerStatefulWidget { ConsumerState createState() => _AppState(); } -class _AppState extends ConsumerState { +class _AppState extends ConsumerState with AfterLayoutMixin { late StreamSubscription _stream; @override @@ -26,6 +28,11 @@ class _AppState extends ConsumerState { _stream = listenSharedData(ref); } + @override + void afterFirstLayout(BuildContext context) { + QuickActionsManager().init(navigatorKey.currentContext!, ref); + } + @override void dispose() { _stream.cancel(); diff --git a/lib/common/actions/add.dart b/lib/common/actions/add.dart index a6837f00..c8ecd0ef 100644 --- a/lib/common/actions/add.dart +++ b/lib/common/actions/add.dart @@ -1,25 +1,28 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import 'package:localmaterialnotes/common/actions/select.dart'; import 'package:localmaterialnotes/common/routing/router.dart'; import 'package:localmaterialnotes/common/routing/router_route.dart'; import 'package:localmaterialnotes/models/note/note.dart'; import 'package:localmaterialnotes/providers/current_note/current_note_provider.dart'; -import 'package:localmaterialnotes/providers/notes/notes_provider.dart'; Future addNote(BuildContext context, WidgetRef ref, {String? content}) async { + exitSelectionMode(ref); + final note = content == null ? Note.empty() : Note.content(content); ref.read(currentNoteProvider.notifier).set(note); - await ref.read(notesProvider.notifier).add(note); - if (!context.mounted) return; + if (!context.mounted) { + return; + } - final route = RouterRoute.editor.fullPath!; + final editorRoute = RouterRoute.editor.fullPath!; final editorParameters = EditorParameters.from({'readonly': false, 'autofocus': true}); // If the editor is already opened with another note, replace the route with the new editor RouterRoute.isEditor - ? context.pushReplacement(route, extra: editorParameters) - : context.push(route, extra: editorParameters); + ? context.pushReplacement(editorRoute, extra: editorParameters) + : context.push(editorRoute, extra: editorParameters); } diff --git a/lib/common/actions/delete.dart b/lib/common/actions/delete.dart index 118fa717..f81edc5e 100644 --- a/lib/common/actions/delete.dart +++ b/lib/common/actions/delete.dart @@ -10,7 +10,9 @@ import 'package:localmaterialnotes/providers/selection_mode/selection_mode_provi import 'package:localmaterialnotes/utils/constants/constants.dart'; Future deleteNote(BuildContext context, WidgetRef ref, Note? note) async { - if (note == null) return false; + if (note == null) { + return false; + } if (await showConfirmationDialog( context, @@ -47,7 +49,9 @@ Future deleteNotes(BuildContext context, WidgetRef ref, List notes) } Future permanentlyDeleteNote(BuildContext context, WidgetRef ref, Note? note) async { - if (note == null) return false; + if (note == null) { + return false; + } if (await showConfirmationDialog( context, diff --git a/lib/common/actions/pin.dart b/lib/common/actions/pin.dart index e160d3f6..6f387c1d 100644 --- a/lib/common/actions/pin.dart +++ b/lib/common/actions/pin.dart @@ -4,7 +4,9 @@ import 'package:localmaterialnotes/models/note/note.dart'; import 'package:localmaterialnotes/providers/notes/notes_provider.dart'; Future togglePinNote(BuildContext context, WidgetRef ref, Note? note) async { - if (note == null) return false; + if (note == null) { + return false; + } await ref.read(notesProvider.notifier).togglePin(note); diff --git a/lib/common/actions/restore.dart b/lib/common/actions/restore.dart index 3f95dd59..a712fc14 100644 --- a/lib/common/actions/restore.dart +++ b/lib/common/actions/restore.dart @@ -8,7 +8,9 @@ import 'package:localmaterialnotes/providers/current_note/current_note_provider. import 'package:localmaterialnotes/utils/constants/constants.dart'; Future restoreNote(BuildContext context, WidgetRef ref, Note? note) async { - if (note == null) return false; + if (note == null) { + return false; + } if (await showConfirmationDialog( context, diff --git a/lib/common/navigation/app_bars/back_menu_app_bar.dart b/lib/common/navigation/app_bars/back_menu_app_bar.dart index 9d184bbc..d3b92fbc 100644 --- a/lib/common/navigation/app_bars/back_menu_app_bar.dart +++ b/lib/common/navigation/app_bars/back_menu_app_bar.dart @@ -25,7 +25,9 @@ class _BackAppBarState extends ConsumerState { Future _onMenuOptionSelected(MenuOption menuOption) async { final note = ref.read(currentNoteProvider); - if (note == null) return; + if (note == null) { + return; + } switch (menuOption) { case MenuOption.togglePin: @@ -53,7 +55,9 @@ class _BackAppBarState extends ConsumerState { void _toggleChecklist() { final editorController = ref.read(editorControllerProvider); - if (editorController == null) return; + if (editorController == null) { + return; + } final isToggled = editorController.getSelectionStyle().containsSame(ParchmentAttribute.block.checkList); editorController.formatSelection( diff --git a/lib/common/navigation/app_bars/search_sort_app_bar.dart b/lib/common/navigation/app_bars/search_sort_app_bar.dart index 51be3317..d0ab26d7 100644 --- a/lib/common/navigation/app_bars/search_sort_app_bar.dart +++ b/lib/common/navigation/app_bars/search_sort_app_bar.dart @@ -27,7 +27,9 @@ class _SearchAppBarState extends ConsumerState { bool sortAscending = SortMethod.ascendingFromPreferences; List _filterNotes(String? search, List notes) { - if (search == null || search.isEmpty) return []; + if (search == null || search.isEmpty) { + return []; + } return notes.where((note) { return note.containsText(search); @@ -117,7 +119,9 @@ class _SearchAppBarState extends ConsumerState { ), ref.watch(provider).when( data: (notes) { - if (notes.isEmpty) return searchButtonPlaceholder; + if (notes.isEmpty) { + return searchButtonPlaceholder; + } return SearchAnchor( viewHintText: localizations.tooltip_search, diff --git a/lib/common/placeholders/empty_placeholder.dart b/lib/common/placeholders/empty_placeholder.dart index dd3cac14..a51a8dfc 100644 --- a/lib/common/placeholders/empty_placeholder.dart +++ b/lib/common/placeholders/empty_placeholder.dart @@ -21,7 +21,9 @@ class EmptyPlaceholder extends StatelessWidget { @override Widget build(BuildContext context) { - if (icon == null || text == null) return Container(); + if (icon == null || text == null) { + return Container(); + } return Center( child: Padding( diff --git a/lib/common/routing/router.dart b/lib/common/routing/router.dart index d8be559d..68126880 100644 --- a/lib/common/routing/router.dart +++ b/lib/common/routing/router.dart @@ -28,7 +28,9 @@ PreferredSizeWidget? _getAppBar(BuildContext context) { } Widget? _getDrawer() { - if (RouterRoute.currentRoute.drawerIndex == null) return null; + if (RouterRoute.currentRoute.drawerIndex == null) { + return null; + } return const SideNavigation(); } @@ -65,7 +67,11 @@ final router = GoRouter( routes: [ GoRoute( path: RouterRoute.editor.path, - builder: (context, state) => EditorPage(state.extra as EditorParameters), + pageBuilder: (context, state) { + return NoTransitionPage( + child: EditorPage(state.extra as EditorParameters), + ); + }, ), ], ), diff --git a/lib/common/routing/router_route.dart b/lib/common/routing/router_route.dart index 3c1955f8..189f3765 100644 --- a/lib/common/routing/router_route.dart +++ b/lib/common/routing/router_route.dart @@ -32,7 +32,9 @@ enum RouterRoute { static int get currentDrawerIndex { final drawerIndex = currentRoute.drawerIndex; - if (drawerIndex == null) throw Exception('No current drawer index'); + if (drawerIndex == null) { + throw Exception('No current drawer index'); + } return drawerIndex; } @@ -40,7 +42,9 @@ enum RouterRoute { static RouterRoute getRouteFromIndex(int index) { final route = values.firstWhereOrNull((route) => route.drawerIndex == index); - if (route == null) throw Exception('No route for index: $index'); + if (route == null) { + throw Exception('No route for index: $index'); + } return route; } diff --git a/lib/common/widgets/note_tile.dart b/lib/common/widgets/note_tile.dart index 9818845c..83ce1feb 100644 --- a/lib/common/widgets/note_tile.dart +++ b/lib/common/widgets/note_tile.dart @@ -54,7 +54,9 @@ class _NoteTileState extends ConsumerState { extra: EditorParameters.from({'readonly': widget.note.deleted, 'autofocus': false}), ); - if (widget.searchView) context.pop(); + if (widget.searchView) { + context.pop(); + } } } @@ -73,11 +75,6 @@ class _NoteTileState extends ConsumerState { @override Widget build(BuildContext context) { - Color? backgroundColor; - if (widget.note.selected) { - backgroundColor = Theme.of(context).colorScheme.surfaceVariant; - } - final isTitleEmpty = widget.note.title.isEmpty; return Dismissible( @@ -147,7 +144,8 @@ class _NoteTileState extends ConsumerState { confirmDismiss: _dismiss, child: ListTile( contentPadding: Paddings.padding16.horizontal.add(Paddings.padding8.vertical), - tileColor: !widget.searchView ? backgroundColor : null, + selected: widget.note.selected, + selectedTileColor: Theme.of(context).colorScheme.surfaceVariant, title: Row( children: [ Expanded( diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 399eed98..a593a0f9 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -28,11 +28,9 @@ "settings_export_json_description": "Export notes to a JSON file (bin included) that can be imported back", "settings_export_markdown_description": "Export notes to a Markdown file (bin included)", "settings_export_success": "The notes were successfully exported.", - "settings_export_fail": "The export failed: {error}.", "settings_import": "Import", "settings_import_description": "Import notes from a JSON file", "settings_import_success": "The notes were successfully imported.", - "settings_import_fail": "The import failed: {error}.", "settings_about": "About", "settings_github": "GitHub", "settings_github_description": "Take a look at the source code", @@ -40,8 +38,8 @@ "settings_licence_description": "AGPL-3.0", "settings_issue": "Report a bug", "settings_issue_description": "Report a bug by creating an issue on GitHub", - "action_add_note": "Add a note", "hint_title": "Title", + "hint_note": "Note", "tooltip_fab_add_note": "Add a note", "tooltip_fab_empty_bin": "Empty the bin", "tooltip_sort": "Sort the notes", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 221d47d4..0b1a40c3 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -28,20 +28,18 @@ "settings_export_json_description": "Exporter les notes dans un fichier JSON (corbeille incluse) qui peut être réimporté", "settings_export_markdown_description": "Exporter les notes dans un fichier Markdown (corbeille incluse)", "settings_export_success": "Les notes ont bien été exportées.", - "settings_export_fail": "L''export a échoué : {error}.", "settings_import": "Importer", "settings_import_description": "Importer les notes depuis un fichier JSON", "settings_import_success": "Les notes ont bien été importées.", - "settings_import_fail": "L''import a échoué : {error}.", "settings_about": "À propos", "settings_github": "GitHub", "settings_github_description": "Jeter un coup d''œil au code source", "settings_licence": "License", + "settings_licence_description": "AGPL-3.0", "settings_issue": "Signaler un bug", "settings_issue_description": "Signaler un bug en créant une issue sur GitHub", - "action_add_note": "Ajouter une note", - "settings_licence_description": "AGPL-3.0", "hint_title": "Titre", + "hint_note": "Note", "tooltip_fab_add_note": "Ajouter une note", "tooltip_fab_empty_bin": "Vider la corbeille", "tooltip_sort": "Trier les notes", diff --git a/lib/l10n/app_localizations.g.dart b/lib/l10n/app_localizations.g.dart index f110cfe7..e9917a90 100644 --- a/lib/l10n/app_localizations.g.dart +++ b/lib/l10n/app_localizations.g.dart @@ -7,6 +7,7 @@ import 'package:intl/intl.dart' as intl; import 'app_localizations_en.g.dart'; import 'app_localizations_fr.g.dart'; +import 'app_localizations_tr.g.dart'; /// Callers can lookup localized strings with an instance of AppLocalizations /// returned by `AppLocalizations.of(context)`. @@ -88,7 +89,7 @@ abstract class AppLocalizations { ]; /// A list of this localizations delegate's supported locales. - static const List supportedLocales = [Locale('en'), Locale('fr')]; + static const List supportedLocales = [Locale('en'), Locale('fr'), Locale('tr')]; /// No description provided for @app_name. /// @@ -264,12 +265,6 @@ abstract class AppLocalizations { /// **'The notes were successfully exported.'** String get settings_export_success; - /// No description provided for @settings_export_fail. - /// - /// In en, this message translates to: - /// **'The export failed: {error}.'** - String settings_export_fail(Object error); - /// No description provided for @settings_import. /// /// In en, this message translates to: @@ -288,12 +283,6 @@ abstract class AppLocalizations { /// **'The notes were successfully imported.'** String get settings_import_success; - /// No description provided for @settings_import_fail. - /// - /// In en, this message translates to: - /// **'The import failed: {error}.'** - String settings_import_fail(Object error); - /// No description provided for @settings_about. /// /// In en, this message translates to: @@ -336,18 +325,18 @@ abstract class AppLocalizations { /// **'Report a bug by creating an issue on GitHub'** String get settings_issue_description; - /// No description provided for @action_add_note. - /// - /// In en, this message translates to: - /// **'Add a note'** - String get action_add_note; - /// No description provided for @hint_title. /// /// In en, this message translates to: /// **'Title'** String get hint_title; + /// No description provided for @hint_note. + /// + /// In en, this message translates to: + /// **'Note'** + String get hint_note; + /// No description provided for @tooltip_fab_add_note. /// /// In en, this message translates to: @@ -670,7 +659,7 @@ class _AppLocalizationsDelegate extends LocalizationsDelegate } @override - bool isSupported(Locale locale) => ['en', 'fr'].contains(locale.languageCode); + bool isSupported(Locale locale) => ['en', 'fr', 'tr'].contains(locale.languageCode); @override bool shouldReload(_AppLocalizationsDelegate old) => false; @@ -683,6 +672,8 @@ AppLocalizations lookupAppLocalizations(Locale locale) { return AppLocalizationsEn(); case 'fr': return AppLocalizationsFr(); + case 'tr': + return AppLocalizationsTr(); } throw FlutterError('AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' diff --git a/lib/l10n/app_localizations_en.g.dart b/lib/l10n/app_localizations_en.g.dart index 2c0cb180..349af062 100644 --- a/lib/l10n/app_localizations_en.g.dart +++ b/lib/l10n/app_localizations_en.g.dart @@ -95,11 +95,6 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settings_export_success => 'The notes were successfully exported.'; - @override - String settings_export_fail(Object error) { - return 'The export failed: $error.'; - } - @override String get settings_import => 'Import'; @@ -109,11 +104,6 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settings_import_success => 'The notes were successfully imported.'; - @override - String settings_import_fail(Object error) { - return 'The import failed: $error.'; - } - @override String get settings_about => 'About'; @@ -136,10 +126,10 @@ class AppLocalizationsEn extends AppLocalizations { String get settings_issue_description => 'Report a bug by creating an issue on GitHub'; @override - String get action_add_note => 'Add a note'; + String get hint_title => 'Title'; @override - String get hint_title => 'Title'; + String get hint_note => 'Note'; @override String get tooltip_fab_add_note => 'Add a note'; diff --git a/lib/l10n/app_localizations_fr.g.dart b/lib/l10n/app_localizations_fr.g.dart index 36c13348..16224711 100644 --- a/lib/l10n/app_localizations_fr.g.dart +++ b/lib/l10n/app_localizations_fr.g.dart @@ -97,11 +97,6 @@ class AppLocalizationsFr extends AppLocalizations { @override String get settings_export_success => 'Les notes ont bien été exportées.'; - @override - String settings_export_fail(Object error) { - return 'L\'export a échoué : $error.'; - } - @override String get settings_import => 'Importer'; @@ -111,11 +106,6 @@ class AppLocalizationsFr extends AppLocalizations { @override String get settings_import_success => 'Les notes ont bien été importées.'; - @override - String settings_import_fail(Object error) { - return 'L\'import a échoué : $error.'; - } - @override String get settings_about => 'À propos'; @@ -138,10 +128,10 @@ class AppLocalizationsFr extends AppLocalizations { String get settings_issue_description => 'Signaler un bug en créant une issue sur GitHub'; @override - String get action_add_note => 'Ajouter une note'; + String get hint_title => 'Titre'; @override - String get hint_title => 'Titre'; + String get hint_note => 'Note'; @override String get tooltip_fab_add_note => 'Ajouter une note'; diff --git a/lib/l10n/app_localizations_tr.g.dart b/lib/l10n/app_localizations_tr.g.dart new file mode 100644 index 00000000..e2c452ee --- /dev/null +++ b/lib/l10n/app_localizations_tr.g.dart @@ -0,0 +1,334 @@ +import 'package:intl/intl.dart' as intl; + +import 'app_localizations.g.dart'; + +/// The translations for Turkish (`tr`). +class AppLocalizationsTr extends AppLocalizations { + AppLocalizationsTr([String locale = 'tr']) : super(locale); + + @override + String get app_name => 'Material Notes'; + + @override + String get app_tagline => 'Basit, çevrimdışı, materyal tasarımlı notlar'; + + @override + String app_about(Object appName) { + return '$appName basitliği hedefleyen metin tabanlı bir not alma uygulamasıdır. Materyal Tasarımı benimser. Notları yerel olarak saklar ve internet izni yoktur, böylece notlara erişebilen tek kişi sizsiniz.'; + } + + @override + String get navigation_notes => 'Notlar'; + + @override + String get navigation_bin => 'Çöp Kutusu'; + + @override + String get navigation_settings => 'Ayarlar'; + + @override + String get error_error => 'Hata'; + + @override + String get error_permission => 'Dosyayı yazma izni alınamadı.'; + + @override + String get error_read_file => 'Dosyayı okuma izni alınamadı.'; + + @override + String get settings_appearance => 'Görünüş'; + + @override + String get settings_theme => 'Tema'; + + @override + String get settings_theme_system => 'Sistem'; + + @override + String get settings_theme_light => 'Açık'; + + @override + String get settings_theme_dark => 'Koyu'; + + @override + String get settings_dynamic_theming => 'Dinamik tema'; + + @override + String get settings_dynamic_theming_description => 'Sisteminizdeki rengi baz alın'; + + @override + String get settings_black_theming => 'Siyah tema'; + + @override + String get settings_black_theming_description => 'Koyu modda siyah arkaplan kullanın'; + + @override + String get settings_language => 'Dil'; + + @override + String get settings_separator => 'Ayırıcıları göster'; + + @override + String get settings_separator_description => 'Notları kolayca ayırt etmek için aralarında bir ayırıcı gösterin'; + + @override + String get settings_behavior => 'Davranış'; + + @override + String get settings_confirmations => 'Onay diyaloglarını göster'; + + @override + String get settings_backup => 'Yedekleme'; + + @override + String get settings_export_json => 'JSON olarak dışa aktar'; + + @override + String get settings_export_markdown => 'Markdown olarak dışa aktar'; + + @override + String get settings_export_json_description => + 'Notları daha sonra kurtarabilmek için bir JSON dosyasına (çöp kutusu dahil) aktarın'; + + @override + String get settings_export_markdown_description => + 'Notları daha sonra kurtarabilmek için bir markdown dosyasına (çöp kutusu dahil) aktarın'; + + @override + String get settings_export_success => 'Dışa aktarma başarılı'; + + @override + String get settings_import => 'İçe aktar'; + + @override + String get settings_import_description => 'JSON dosyasından içe aktar'; + + @override + String get settings_import_success => 'İçe aktarma başarılı.'; + + @override + String get settings_about => 'Hakkında'; + + @override + String get settings_github => 'GitHub'; + + @override + String get settings_github_description => 'Kaynak koduna göz at'; + + @override + String get settings_licence => 'Lisans'; + + @override + String get settings_licence_description => 'AGPL-3.0'; + + @override + String get settings_issue => 'Hata bildir'; + + @override + String get settings_issue_description => 'GitHub\'da bir issue oluşturarak bir hata bildirin'; + + @override + String get hint_title => 'Başlık'; + + @override + String get hint_note => 'Note'; + + @override + String get tooltip_fab_add_note => 'Bir not ekle'; + + @override + String get tooltip_fab_empty_bin => 'Çöp kutusunu boşalt'; + + @override + String get tooltip_sort => 'Notları sırala'; + + @override + String get tooltip_search => 'Notların içinde ara'; + + @override + String get tooltip_toggle_checkbox => 'Onay kutusunu aç/kapat'; + + @override + String get tooltip_select_all => 'Tümünü seç'; + + @override + String get tooltip_unselect_all => 'Tümünün seçimini kaldır'; + + @override + String get tooltip_delete => 'Sil'; + + @override + String get tooltip_permanently_delete => 'Kalıcı sil'; + + @override + String get tooltip_restore => 'Kurtar'; + + @override + String get tooltip_toggle_pins => 'Sabitlemeyi aç/kapat'; + + @override + String get button_ok => 'Tamam'; + + @override + String get button_close => 'Kapat'; + + @override + String get button_cancel => 'İptal et'; + + @override + String get button_add => 'Ekle'; + + @override + String get dialog_delete => 'Sil'; + + @override + String dialog_delete_body(num count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'notu', + one: 'notu', + zero: '', + ); + String _temp1 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'onları', + one: 'onu', + zero: '', + ); + return 'Gerçekten $count $_temp0 silmek istiyor musunuz? Çöp kutusundan $_temp1 kurtarabilirsiniz.'; + } + + @override + String get dialog_delete_body_single => 'Bu notu gerçekten silmek istiyor musunuz?Çöp kutusundan kurtarabilirsiniz.'; + + @override + String get dialog_permanently_delete => 'Kalıcı sil'; + + @override + String dialog_permanently_delete_body(num count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'notu', + one: 'notu', + zero: '', + ); + String _temp1 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'Onları', + one: 'Onu', + zero: '', + ); + return 'Gerçekten $count $_temp0 kalıcı olarak silmek istiyor musunuz?$_temp1 kurtaramazsınız.'; + } + + @override + String get dialog_permanently_delete_body_single => + 'Bu notu gerçekten kalıcı olarak silmek istiyor musunuz?Kurtarmanız mümkün olmayacaktır.'; + + @override + String get dialog_restore => 'Kurtar'; + + @override + String dialog_restore_body(num count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'notu', + one: 'notu', + zero: '', + ); + return 'Gerçekten $count $_temp0 kurtarmak istiyor musunuz?'; + } + + @override + String get dialog_restore_body_single => 'Bu notu gerçekten kurtarmak istiyor musunuz?'; + + @override + String get dialog_empty_bin => 'Çöp kutusunu boşalt'; + + @override + String get dialog_empty_bin_body => + 'Çöp kutusunu gerçekten kalıcı olarak boşaltmak istiyor musunuz? İçerdiği notları kurtaramazsınız'; + + @override + String get sort_date => 'Tarih'; + + @override + String get sort_title => 'Başlık'; + + @override + String get sort_ascending => 'Artan'; + + @override + String get placeholder_notes => 'Not yok'; + + @override + String get placeholder_bin => 'Çöp kutusu boş'; + + @override + String get menu_pin => 'Sabitle'; + + @override + String get menu_share => 'Paylaş'; + + @override + String get menu_unpin => 'Sabitleme'; + + @override + String get menu_delete => 'Sil'; + + @override + String get menu_restore => 'Kurtar'; + + @override + String get menu_delete_permanently => 'Kalıcı Sil'; + + @override + String get menu_about => 'Hakkında'; + + @override + String get notes_untitled => 'Başlıksız not'; + + @override + String get confirmations_title_none => 'Asla'; + + @override + String get confirmations_title_irreversible => 'Sadece geri alınamaz eylemler'; + + @override + String get confirmations_title_all => 'Her zaman'; + + @override + String get dismiss_pin => 'Sabitle'; + + @override + String get dismiss_unpin => 'Sabitleme'; + + @override + String get dismiss_delete => 'Sil'; + + @override + String get dismiss_permanently_delete => 'Kalıcı sil'; + + @override + String get dismiss_restore => 'Kurtar'; + + @override + String get about_last_edited => 'Son düzenleme'; + + @override + String get about_created => 'Oluşturma tarihi'; + + @override + String get about_words => 'Kelime'; + + @override + String get about_characters => 'Karakter'; + + @override + String get time_at => ''; +} diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb new file mode 100644 index 00000000..a6dbee1a --- /dev/null +++ b/lib/l10n/app_tr.arb @@ -0,0 +1,95 @@ +{ + "app_name": "Material Notes", + "app_tagline": "Basit, çevrimdışı, materyal tasarımlı notlar", + "app_about": "{appName} basitliği hedefleyen metin tabanlı bir not alma uygulamasıdır. Materyal Tasarımı benimser. Notları yerel olarak saklar ve internet izni yoktur, böylece notlara erişebilen tek kişi sizsiniz.", + "navigation_notes": "Notlar", + "navigation_bin": "Çöp Kutusu", + "navigation_settings": "Ayarlar", + "error_error": "Hata", + "error_permission": "Dosyayı yazma izni alınamadı.", + "error_read_file": "Dosyayı okuma izni alınamadı.", + "settings_appearance": "Görünüş", + "settings_theme": "Tema", + "settings_theme_system": "Sistem", + "settings_theme_light": "Açık", + "settings_theme_dark": "Koyu", + "settings_dynamic_theming": "Dinamik tema", + "settings_dynamic_theming_description": "Sisteminizdeki rengi baz alın", + "settings_black_theming": "Siyah tema", + "settings_black_theming_description": "Koyu modda siyah arkaplan kullanın", + "settings_language": "Dil", + "settings_separator": "Ayırıcıları göster", + "settings_separator_description": "Notları kolayca ayırt etmek için aralarında bir ayırıcı gösterin", + "settings_behavior": "Davranış", + "settings_confirmations": "Onay diyaloglarını göster", + "settings_backup": "Yedekleme", + "settings_export_json": "JSON olarak dışa aktar", + "settings_export_markdown": "Markdown olarak dışa aktar", + "settings_export_json_description": "Notları daha sonra kurtarabilmek için bir JSON dosyasına (çöp kutusu dahil) aktarın", + "settings_export_markdown_description": "Notları daha sonra kurtarabilmek için bir markdown dosyasına (çöp kutusu dahil) aktarın", + "settings_export_success": "Dışa aktarma başarılı", + "settings_import": "İçe aktar", + "settings_import_description": "JSON dosyasından içe aktar", + "settings_import_success": "İçe aktarma başarılı.", + "settings_about": "Hakkında", + "settings_github": "GitHub", + "settings_github_description": "Kaynak koduna göz at", + "settings_licence": "Lisans", + "settings_licence_description": "AGPL-3.0", + "settings_issue": "Hata bildir", + "settings_issue_description": "GitHub''da bir issue oluşturarak bir hata bildirin", + "hint_title": "Başlık", + "hint_note": "Note", + "tooltip_fab_add_note": "Bir not ekle", + "tooltip_fab_empty_bin": "Çöp kutusunu boşalt", + "tooltip_sort": "Notları sırala", + "tooltip_search": "Notların içinde ara", + "tooltip_toggle_checkbox": "Onay kutusunu aç/kapat", + "tooltip_select_all": "Tümünü seç", + "tooltip_unselect_all": "Tümünün seçimini kaldır", + "tooltip_delete": "Sil", + "tooltip_permanently_delete": "Kalıcı sil", + "tooltip_restore": "Kurtar", + "tooltip_toggle_pins": "Sabitlemeyi aç/kapat", + "button_ok": "Tamam", + "button_close": "Kapat", + "button_cancel": "İptal et", + "button_add": "Ekle", + "dialog_delete": "Sil", + "dialog_delete_body": "Gerçekten {count} {count, plural, zero{} one{notu} other{notu}} silmek istiyor musunuz? Çöp kutusundan {count, plural, zero{} one{onu} other{onları}} kurtarabilirsiniz.", + "dialog_delete_body_single": "Bu notu gerçekten silmek istiyor musunuz?Çöp kutusundan kurtarabilirsiniz.", + "dialog_permanently_delete": "Kalıcı sil", + "dialog_permanently_delete_body": "Gerçekten {count} {count, plural, zero{} one{notu} other{notu}} kalıcı olarak silmek istiyor musunuz?{count, plural, zero{} one{Onu} other{Onları}} kurtaramazsınız.", + "dialog_permanently_delete_body_single": "Bu notu gerçekten kalıcı olarak silmek istiyor musunuz?Kurtarmanız mümkün olmayacaktır.", + "dialog_restore": "Kurtar", + "dialog_restore_body": "Gerçekten {count} {count, plural, zero{} one{notu} other{notu}} kurtarmak istiyor musunuz?", + "dialog_restore_body_single": "Bu notu gerçekten kurtarmak istiyor musunuz?", + "dialog_empty_bin": "Çöp kutusunu boşalt", + "dialog_empty_bin_body": "Çöp kutusunu gerçekten kalıcı olarak boşaltmak istiyor musunuz? İçerdiği notları kurtaramazsınız", + "sort_date": "Tarih", + "sort_title": "Başlık", + "sort_ascending": "Artan", + "placeholder_notes": "Not yok", + "placeholder_bin": "Çöp kutusu boş", + "menu_pin": "Sabitle", + "menu_share": "Paylaş", + "menu_unpin": "Sabitleme", + "menu_delete": "Sil", + "menu_restore": "Kurtar", + "menu_delete_permanently": "Kalıcı Sil", + "menu_about": "Hakkında", + "notes_untitled": "Başlıksız not", + "confirmations_title_none": "Asla", + "confirmations_title_irreversible": "Sadece geri alınamaz eylemler", + "confirmations_title_all": "Her zaman", + "dismiss_pin": "Sabitle", + "dismiss_unpin": "Sabitleme", + "dismiss_delete": "Sil", + "dismiss_permanently_delete": "Kalıcı sil", + "dismiss_restore": "Kurtar", + "about_last_edited": "Son düzenleme", + "about_created": "Oluşturma tarihi", + "about_words": "Kelime", + "about_characters": "Karakter", + "time_at": "" +} \ No newline at end of file diff --git a/lib/l10n/hardcoded_localizations.dart b/lib/l10n/hardcoded_localizations.dart new file mode 100644 index 00000000..8735cc4f --- /dev/null +++ b/lib/l10n/hardcoded_localizations.dart @@ -0,0 +1,81 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:localmaterialnotes/models/note/note.dart'; +import 'package:localmaterialnotes/utils/constants/constants.dart'; +import 'package:localmaterialnotes/utils/locale_manager.dart'; + +// All strings here are hardcoded because they are needed when no context is available, while AppLocalizations needs one + +/// App name. +const _appName = 'Material Notes'; + +/// All supported localizations. +enum SupportedLocalizations { + english(Locale('en')), + french(Locale('fr')), + turkish(Locale('tr')), + ; + + final Locale locale; + + const SupportedLocalizations(this.locale); +} + +/// Title for the quick action to add a note. +String get actionAddNoteTitle { + const englishDefault = 'Add a note'; + + final locale = LocaleManager().locale; + + final String title; + + if (locale == SupportedLocalizations.english.locale) { + title = englishDefault; + } else if (locale == SupportedLocalizations.french.locale) { + title = 'Ajouter une note'; + } else if (locale == SupportedLocalizations.turkish.locale) { + title = 'Not ekle'; + } else { + log('Missing add note quick action string for locale: $locale'); + title = englishDefault; + } + + return title; +} + +/// Title and content of the welcome note. +Note get welcomeNote { + const englishDefaultTitle = 'Welcome to $_appName!'; + const englishDefaultContent = 'Simple, local, material design notes'; + + final locale = LocaleManager().locale; + + final String title; + final String content; + + if (locale == SupportedLocalizations.english.locale) { + title = englishDefaultTitle; + content = englishDefaultContent; + } else if (locale == SupportedLocalizations.french.locale) { + title = 'Bienvenue dans $_appName !'; + content = 'Notes simples, locales, en material design'; + } else if (locale == SupportedLocalizations.turkish.locale) { + title = "$_appName'a hoşgeldin!"; + content = 'Basit, çevrimdışı, materyal tasarımlı notlar'; + } else { + log('Missing welcome note strings for locale: $locale'); + title = englishDefaultTitle; + content = englishDefaultContent; + } + + return Note( + id: uuid.v4(), + deleted: false, + pinned: true, + createdTime: DateTime.now(), + editedTime: DateTime.now(), + title: title, + content: '[{"insert":"$content\\n\\n"}]', + ); +} diff --git a/lib/main.dart b/lib/main.dart index 3c726f85..21056633 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_web_plugins/url_strategy.dart'; // ignore: depend_on_referenced_packages import 'package:localmaterialnotes/app.dart'; import 'package:localmaterialnotes/utils/database_manager.dart'; import 'package:localmaterialnotes/utils/info_manager.dart'; @@ -26,8 +25,6 @@ Future main() async { await ThemeManager().init(); await DatabaseManager().init(); - usePathUrlStrategy(); - FlutterNativeSplash.remove(); runApp( diff --git a/lib/models/note/note.dart b/lib/models/note/note.dart index 9ba4aad1..1bcdad1c 100644 --- a/lib/models/note/note.dart +++ b/lib/models/note/note.dart @@ -13,6 +13,8 @@ part 'note.g.dart'; @JsonSerializable() @Collection(inheritance: false) class Note extends Equatable { + static const String _emptyContent = '[{"insert":"\\n"}]'; + @JsonKey(includeFromJson: false, includeToJson: false) String? id; @Index() @@ -44,7 +46,7 @@ class Note extends Equatable { createdTime: DateTime.now(), editedTime: DateTime.now(), title: '', - content: '[{"insert":"\\n"}]', + content: _emptyContent, ); factory Note.content(String content) => Note( @@ -121,6 +123,10 @@ class Note extends Equatable { return ParchmentDocument.fromJson(jsonDecode(content) as List); } + bool get isEmpty { + return title.isEmpty && content == _emptyContent; + } + bool containsText(String search) { final searchCleaned = search.toLowerCase().trim(); diff --git a/lib/models/note/note.g.dart b/lib/models/note/note.g.dart index fe234b7a..7342e4bc 100644 --- a/lib/models/note/note.g.dart +++ b/lib/models/note/note.g.dart @@ -42,13 +42,18 @@ const NoteSchema = CollectionSchema( name: r'id', type: IsarType.string, ), - r'pinned': PropertySchema( + r'isEmpty': PropertySchema( id: 5, + name: r'isEmpty', + type: IsarType.bool, + ), + r'pinned': PropertySchema( + id: 6, name: r'pinned', type: IsarType.bool, ), r'title': PropertySchema( - id: 6, + id: 7, name: r'title', type: IsarType.string, ) @@ -122,8 +127,9 @@ void _noteSerialize( writer.writeBool(offsets[2], object.deleted); writer.writeDateTime(offsets[3], object.editedTime); writer.writeString(offsets[4], object.id); - writer.writeBool(offsets[5], object.pinned); - writer.writeString(offsets[6], object.title); + writer.writeBool(offsets[5], object.isEmpty); + writer.writeBool(offsets[6], object.pinned); + writer.writeString(offsets[7], object.title); } Note _noteDeserialize( @@ -138,8 +144,8 @@ Note _noteDeserialize( deleted: reader.readBool(offsets[2]), editedTime: reader.readDateTime(offsets[3]), id: reader.readStringOrNull(offsets[4]), - pinned: reader.readBool(offsets[5]), - title: reader.readString(offsets[6]), + pinned: reader.readBool(offsets[6]), + title: reader.readString(offsets[7]), ); return object; } @@ -164,6 +170,8 @@ P _noteDeserializeProp

( case 5: return (reader.readBool(offset)) as P; case 6: + return (reader.readBool(offset)) as P; + case 7: return (reader.readString(offset)) as P; default: throw IsarError('Unknown property with id $propertyId'); @@ -737,6 +745,15 @@ extension NoteQueryFilter on QueryBuilder { }); } + QueryBuilder isEmptyEqualTo(bool value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'isEmpty', + value: value, + )); + }); + } + QueryBuilder isarIdEqualTo(Id value) { return QueryBuilder.apply(this, (query) { return query.addFilterCondition(FilterCondition.equalTo( @@ -990,6 +1007,18 @@ extension NoteQuerySortBy on QueryBuilder { }); } + QueryBuilder sortByIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isEmpty', Sort.asc); + }); + } + + QueryBuilder sortByIsEmptyDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isEmpty', Sort.desc); + }); + } + QueryBuilder sortByPinned() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'pinned', Sort.asc); @@ -1076,6 +1105,18 @@ extension NoteQuerySortThenBy on QueryBuilder { }); } + QueryBuilder thenByIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isEmpty', Sort.asc); + }); + } + + QueryBuilder thenByIsEmptyDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'isEmpty', Sort.desc); + }); + } + QueryBuilder thenByIsarId() { return QueryBuilder.apply(this, (query) { return query.addSortBy(r'isarId', Sort.asc); @@ -1144,6 +1185,12 @@ extension NoteQueryWhereDistinct on QueryBuilder { }); } + QueryBuilder distinctByIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'isEmpty'); + }); + } + QueryBuilder distinctByPinned() { return QueryBuilder.apply(this, (query) { return query.addDistinctBy(r'pinned'); @@ -1194,6 +1241,12 @@ extension NoteQueryProperty on QueryBuilder { }); } + QueryBuilder isEmptyProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'isEmpty'); + }); + } + QueryBuilder pinnedProperty() { return QueryBuilder.apply(this, (query) { return query.addPropertyName(r'pinned'); diff --git a/lib/pages/bin/bin_page.dart b/lib/pages/bin/bin_page.dart index 75322273..558e7ffc 100644 --- a/lib/pages/bin/bin_page.dart +++ b/lib/pages/bin/bin_page.dart @@ -22,29 +22,36 @@ class _BinPageState extends ConsumerState { Widget build(BuildContext context) { return ref.watch(binProvider).when( data: (notes) { - if (notes.isEmpty) return EmptyPlaceholder.bin(); + if (notes.isEmpty) { + return EmptyPlaceholder.bin(); + } final useSeparators = PreferencesManager().get(PreferenceKey.separator) ?? PreferenceKey.separator.defaultValue! as bool; - return useSeparators - ? ListView.separated( - padding: Paddings.custom.fab, - itemCount: notes.length, - itemBuilder: (context, index) { - return NoteTile(notes[index]); - }, - separatorBuilder: (BuildContext context, int index) { - return Separator.divider1indent8.horizontal; - }, - ) - : ListView.builder( - padding: Paddings.custom.fab, - itemCount: notes.length, - itemBuilder: (context, index) { - return NoteTile(notes[index]); - }, - ); + // Wrap with Material to fix the tile background color not updating in real time + // when the tile is selected and the view is scrolled + // see: https://github.com/flutter/flutter/issues/86584 + return Material( + child: useSeparators + ? ListView.separated( + padding: Paddings.custom.fab, + itemCount: notes.length, + itemBuilder: (context, index) { + return NoteTile(notes[index]); + }, + separatorBuilder: (BuildContext context, int index) { + return Separator.divider1indent8.horizontal; + }, + ) + : ListView.builder( + padding: Paddings.custom.fab, + itemCount: notes.length, + itemBuilder: (context, index) { + return NoteTile(notes[index]); + }, + ), + ); }, error: (error, stackTrace) { return const ErrorPlaceholder(); diff --git a/lib/pages/editor/about_sheet.dart b/lib/pages/editor/about_sheet.dart index 1a3dd56f..69ae7203 100644 --- a/lib/pages/editor/about_sheet.dart +++ b/lib/pages/editor/about_sheet.dart @@ -12,7 +12,9 @@ class AboutSheet extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final note = ref.watch(currentNoteProvider); - if (note == null) return const ErrorPlaceholder(); + if (note == null) { + return const ErrorPlaceholder(); + } return ListView( shrinkWrap: true, diff --git a/lib/pages/editor/editor_page.dart b/lib/pages/editor/editor_page.dart index f4f29391..a8335b7a 100644 --- a/lib/pages/editor/editor_page.dart +++ b/lib/pages/editor/editor_page.dart @@ -28,22 +28,29 @@ class EditorPage extends ConsumerStatefulWidget { class _EditorState extends ConsumerState { final titleController = TextEditingController(); - late FleatherController fleatherController; - final fleatherFocusNode = FocusNode(); + FleatherController? fleatherController; void _synchronizeTitle(Note note, String? newTitle) { - if (newTitle == null) return; + if (newTitle == null) { + return; + } ref.read(notesProvider.notifier).edit(note..title = newTitle); } void _synchronizeContent(Note note) { - note.content = jsonEncode(fleatherController.document.toDelta().toJson()); + if (fleatherController == null) { + return; + } + + note.content = jsonEncode(fleatherController!.document.toDelta().toJson()); ref.read(notesProvider.notifier).edit(note); } void _launchUrl(String? url) { - if (url == null) return; + if (url == null) { + return; + } launchUrlString(url); } @@ -52,15 +59,20 @@ class _EditorState extends ConsumerState { Widget build(BuildContext context) { final note = ref.watch(currentNoteProvider); - if (note == null) return const LoadingPlaceholder(); + if (note == null) { + return const LoadingPlaceholder(); + } titleController.text = note.title; - fleatherController = FleatherController(document: note.document); - fleatherController.addListener(() => _synchronizeContent(note)); - Future(() { - ref.read(editorControllerProvider.notifier).set(fleatherController); - }); + if (fleatherController == null) { + fleatherController = FleatherController(document: note.document); + fleatherController!.addListener(() => _synchronizeContent(note)); + + Future(() { + ref.read(editorControllerProvider.notifier).set(fleatherController!); + }); + } return Padding( padding: Paddings.custom.pageButBottom, @@ -68,7 +80,6 @@ class _EditorState extends ConsumerState { children: [ TextField( readOnly: widget._readOnly, - autofocus: widget._autofocus, textCapitalization: TextCapitalization.sentences, textInputAction: TextInputAction.next, style: Theme.of(context).textTheme.titleLarge, @@ -80,11 +91,14 @@ class _EditorState extends ConsumerState { ), Padding(padding: Paddings.padding8.vertical), Expanded( - child: FleatherEditor( - controller: fleatherController, - focusNode: fleatherFocusNode, + child: FleatherField( + controller: fleatherController!, + autofocus: widget._autofocus, readOnly: widget._readOnly, expands: true, + decoration: InputDecoration.collapsed( + hintText: localizations.hint_note, + ), onLaunchUrl: _launchUrl, spellCheckConfiguration: SpellCheckConfiguration( spellCheckService: DefaultSpellCheckService(), diff --git a/lib/pages/notes/notes_page.dart b/lib/pages/notes/notes_page.dart index 4e180acf..204121dc 100644 --- a/lib/pages/notes/notes_page.dart +++ b/lib/pages/notes/notes_page.dart @@ -9,7 +9,6 @@ import 'package:localmaterialnotes/utils/constants/paddings.dart'; import 'package:localmaterialnotes/utils/constants/separators.dart'; import 'package:localmaterialnotes/utils/preferences/preference_key.dart'; import 'package:localmaterialnotes/utils/preferences/preferences_manager.dart'; -import 'package:localmaterialnotes/utils/quick_actions_manager.dart'; class NotesPage extends ConsumerStatefulWidget { const NotesPage(); @@ -21,33 +20,38 @@ class NotesPage extends ConsumerStatefulWidget { class _NotesPageState extends ConsumerState { @override Widget build(BuildContext context) { - QuickActionsManager().init(context, ref); - return ref.watch(notesProvider).when( data: (notes) { - if (notes.isEmpty) return EmptyPlaceholder.notes(); + if (notes.isEmpty) { + return EmptyPlaceholder.notes(); + } final useSeparators = PreferencesManager().get(PreferenceKey.separator) ?? PreferenceKey.separator.defaultValue! as bool; - return useSeparators - ? ListView.separated( - padding: Paddings.custom.fab, - itemCount: notes.length, - itemBuilder: (context, index) { - return NoteTile(notes[index]); - }, - separatorBuilder: (BuildContext context, int index) { - return Separator.divider1indent8.horizontal; - }, - ) - : ListView.builder( - padding: Paddings.custom.fab, - itemCount: notes.length, - itemBuilder: (context, index) { - return NoteTile(notes[index]); - }, - ); + // Wrap with Material to fix the tile background color not updating in real time + // when the tile is selected and the view is scrolled + // see: https://github.com/flutter/flutter/issues/86584 + return Material( + child: useSeparators + ? ListView.separated( + padding: Paddings.custom.fab, + itemCount: notes.length, + itemBuilder: (context, index) { + return NoteTile(notes[index]); + }, + separatorBuilder: (BuildContext context, int index) { + return Separator.divider1indent8.horizontal; + }, + ) + : ListView.builder( + padding: Paddings.custom.fab, + itemCount: notes.length, + itemBuilder: (context, index) { + return NoteTile(notes[index]); + }, + ), + ); }, error: (error, stackTrace) { return const ErrorPlaceholder(); diff --git a/lib/pages/settings/interactions.dart b/lib/pages/settings/interactions.dart index 06c30e38..f41d61b2 100644 --- a/lib/pages/settings/interactions.dart +++ b/lib/pages/settings/interactions.dart @@ -39,7 +39,9 @@ class Interactions { ); }, ).then((locale) async { - if (locale == null) return; + if (locale == null) { + return; + } LocaleManager().setLocale(locale); await Restart.restartApp(); @@ -79,7 +81,9 @@ class Interactions { ); }, ).then((themeMode) { - if (themeMode == null) return; + if (themeMode == null) { + return; + } ThemeManager().setThemeMode(themeMode); }); @@ -118,7 +122,9 @@ class Interactions { ); }, ).then((confirmationsValue) { - if (confirmationsValue == null) return; + if (confirmationsValue == null) { + return; + } PreferencesManager().set(PreferenceKey.confirmations.name, confirmationsValue.name); }); @@ -126,38 +132,38 @@ class Interactions { Future backupAsJson(BuildContext context) async { try { - await DatabaseManager().exportAsJson(); + if (await DatabaseManager().exportAsJson()) { + SnackBarManager.info(localizations.settings_export_success).show(); + } } catch (exception, stackTrace) { log(exception.toString(), stackTrace: stackTrace); - SnackBarManager.info(localizations.settings_export_fail(exception.toString())).show(); - return; - } - SnackBarManager.info(localizations.settings_export_success).show(); + SnackBarManager.info(exception.toString()).show(); + } } Future backupAsMarkdown(BuildContext context) async { try { - await DatabaseManager().exportAsMarkdown(); + if (await DatabaseManager().exportAsMarkdown()) { + SnackBarManager.info(localizations.settings_export_success).show(); + } } catch (exception, stackTrace) { log(exception.toString(), stackTrace: stackTrace); - SnackBarManager.info(localizations.settings_export_fail(exception.toString())).show(); - return; - } - SnackBarManager.info(localizations.settings_export_success).show(); + SnackBarManager.info(exception.toString()).show(); + } } Future restore(BuildContext context) async { try { - await DatabaseManager().import(); + if (await DatabaseManager().import()) { + SnackBarManager.info(localizations.settings_import_success).show(); + } } catch (exception, stackTrace) { log(exception.toString(), stackTrace: stackTrace); - SnackBarManager.info(localizations.settings_import_fail(exception.toString())).show(); - return; - } - SnackBarManager.info(localizations.settings_import_success).show(); + SnackBarManager.info(exception.toString()).show(); + } } Future showAbout(BuildContext context) async { diff --git a/lib/providers/notes/notes_provider.dart b/lib/providers/notes/notes_provider.dart index 52b43b1d..5e30ff2f 100644 --- a/lib/providers/notes/notes_provider.dart +++ b/lib/providers/notes/notes_provider.dart @@ -33,28 +33,17 @@ class Notes extends _$Notes with BaseProvider { await get(); } - Future add(Note newNote) async { - state = const AsyncLoading(); - - try { - await databaseManager.add(newNote); - } on Exception catch (exception, stackTrace) { - log(exception.toString(), stackTrace: stackTrace); - return false; - } - - await get(); - - return true; - } - Future edit(Note editedNote) async { state = const AsyncLoading(); editedNote.editedTime = DateTime.now(); try { - await databaseManager.edit(editedNote); + if (editedNote.isEmpty) { + await databaseManager.delete(editedNote.isarId); + } else { + await databaseManager.edit(editedNote); + } } on Exception catch (exception, stackTrace) { log(exception.toString(), stackTrace: stackTrace); return false; diff --git a/lib/providers/notes/notes_provider.g.dart b/lib/providers/notes/notes_provider.g.dart index 55abb91c..425712cc 100644 --- a/lib/providers/notes/notes_provider.g.dart +++ b/lib/providers/notes/notes_provider.g.dart @@ -6,7 +6,7 @@ part of 'notes_provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$notesHash() => r'b8e744a80700bcb1d12839e0860e7fe6dbf9252b'; +String _$notesHash() => r'e67e4eac7877a97c44ac7e8e097ff30e3e2165a4'; /// See also [Notes]. @ProviderFor(Notes) diff --git a/lib/utils/constants/paddings.dart b/lib/utils/constants/paddings.dart index 8b668178..17c57cca 100644 --- a/lib/utils/constants/paddings.dart +++ b/lib/utils/constants/paddings.dart @@ -11,6 +11,8 @@ enum Paddings { padding64(64), ; + double get bottomSystemUiPadding => MediaQuery.of(navigatorKey.currentContext!).padding.bottom; + EdgeInsets get zero => EdgeInsets.zero; EdgeInsets get all => EdgeInsets.all(_padding); @@ -27,9 +29,9 @@ enum Paddings { EdgeInsets get bottom => EdgeInsets.only(bottom: _padding); - EdgeInsets get bottomSystemUi => EdgeInsets.only(bottom: MediaQuery.of(navigatorKey.currentContext!).padding.bottom); + EdgeInsets get bottomSystemUi => EdgeInsets.only(bottom: bottomSystemUiPadding); - EdgeInsets get fab => const EdgeInsets.only(bottom: kFloatingActionButtonMargin + 64); + EdgeInsets get fab => EdgeInsets.only(bottom: bottomSystemUiPadding + kFloatingActionButtonMargin + 64); EdgeInsets get page => const EdgeInsets.all(16); diff --git a/lib/utils/database_manager.dart b/lib/utils/database_manager.dart index be26b94f..a44e2514 100644 --- a/lib/utils/database_manager.dart +++ b/lib/utils/database_manager.dart @@ -1,13 +1,12 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'dart:ui'; import 'package:is_first_run/is_first_run.dart'; import 'package:isar/isar.dart'; +import 'package:localmaterialnotes/l10n/hardcoded_localizations.dart'; import 'package:localmaterialnotes/models/note/note.dart'; import 'package:localmaterialnotes/utils/constants/constants.dart'; import 'package:localmaterialnotes/utils/extensions/date_time_extensions.dart'; -import 'package:localmaterialnotes/utils/locale_manager.dart'; import 'package:localmaterialnotes/utils/preferences/sort_method.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_storage/shared_storage.dart' as saf; @@ -34,7 +33,7 @@ class DatabaseManager { ); if (await IsFirstRun.isFirstCall()) { - await add(_welcomeNote); + await add(welcomeNote); } } @@ -88,14 +87,14 @@ class DatabaseManager { }); } - Future exportAsJson() async { + Future exportAsJson() async { final notes = await getAll(); final notesAsJson = jsonEncode(notes); - await _export('application/json', 'json', notesAsJson); + return await _export('application/json', 'json', notesAsJson); } - Future exportAsMarkdown() async { + Future exportAsMarkdown() async { final notes = await getAll(); final StringBuffer notesAsMarkdown = StringBuffer('# Material Notes\n\n'); for (final note in notes) { @@ -103,13 +102,15 @@ class DatabaseManager { .writeln('## ${note.title}${note.contentDisplay.isNotEmpty ? '\n\n' : ''}${note.contentDisplay}\n'); } - await _export('text/markdown', 'md', notesAsMarkdown.toString().trim()); + return await _export('text/markdown', 'md', notesAsMarkdown.toString().trim()); } - Future _export(String mimeType, String extension, String notesAsString) async { + Future _export(String mimeType, String extension, String notesAsString) async { final exportDirectory = await saf.openDocumentTree(); - if (exportDirectory == null) throw Exception(localizations.error_permission); + if (exportDirectory == null) { + return false; + } final timestamp = DateTime.timestamp(); @@ -119,52 +120,32 @@ class DatabaseManager { displayName: 'materialnotes_export_${timestamp.filename}.$extension', bytes: Uint8List.fromList(utf8.encode(notesAsString)), ); + + return true; } - Future import() async { + Future import() async { final importFiles = await saf.openDocument( grantWritePermission: false, mimeType: 'application/json', ); - if (importFiles == null || importFiles.isEmpty) throw Exception(localizations.error_permission); + if (importFiles == null || importFiles.isEmpty) { + return false; + } final importedData = await saf.getDocumentContent(importFiles.first); - if (importedData == null) throw Exception(localizations.error_read_file); + if (importedData == null) { + throw Exception(localizations.error_read_file); + } final importedString = utf8.decode(importedData); final notesJson = jsonDecode(importedString) as List; final notes = notesJson.map((e) => Note.fromJson(e as Map)).toList(); await addAll(notes); - } - - /// Hardcode the welcome note translations here because no context is available when it's used - Note get _welcomeNote { - final locale = LocaleManager().locale; - - final String title; - final String content; - - if (locale == const Locale('en')) { - title = 'Welcome to Material Notes!'; - content = 'Simple, local, material design notes'; - } else if (locale == const Locale('fr')) { - title = 'Bienvenue dans Material Notes !'; - content = 'Notes simples, locales, en material design'; - } else { - throw Exception('Missing welcome note for locale: $locale'); - } - return Note( - id: uuid.v4(), - deleted: false, - pinned: true, - createdTime: DateTime.now(), - editedTime: DateTime.now(), - title: title, - content: '[{"insert":"$content\\n\\n"}]', - ); + return true; } } diff --git a/lib/utils/locale_manager.dart b/lib/utils/locale_manager.dart index 7d48a754..111662a2 100644 --- a/lib/utils/locale_manager.dart +++ b/lib/utils/locale_manager.dart @@ -26,7 +26,9 @@ class LocaleManager { } void setLocale(Locale? locale) { - if (locale == null) return; + if (locale == null) { + return; + } PreferencesManager().set(PreferenceKey.locale.name, locale.languageCode); } diff --git a/lib/utils/preferences/preferences_manager.dart b/lib/utils/preferences/preferences_manager.dart index 23e1dc87..2a565d13 100644 --- a/lib/utils/preferences/preferences_manager.dart +++ b/lib/utils/preferences/preferences_manager.dart @@ -17,7 +17,9 @@ class PreferencesManager { } void set(String key, T value) { - if (T == dynamic) throw ArgumentError('The type T is required.'); + if (T == dynamic) { + throw ArgumentError('The type T is required.'); + } if (T == bool) { _preferences.setBool(key, value as bool); @@ -33,7 +35,9 @@ class PreferencesManager { } T? get(PreferenceKey preferenceKey) { - if (T == dynamic) throw ArgumentError('The type T is required.'); + if (T == dynamic) { + throw ArgumentError('The type T is required.'); + } return _preferences.get(preferenceKey.name) as T?; } diff --git a/lib/utils/quick_actions_manager.dart b/lib/utils/quick_actions_manager.dart index 1bbe9135..6fdcc220 100644 --- a/lib/utils/quick_actions_manager.dart +++ b/lib/utils/quick_actions_manager.dart @@ -1,7 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:localmaterialnotes/common/actions/add.dart'; -import 'package:localmaterialnotes/l10n/app_localizations.g.dart'; +import 'package:localmaterialnotes/l10n/hardcoded_localizations.dart'; import 'package:quick_actions/quick_actions.dart'; class QuickActionsManager { @@ -19,8 +19,8 @@ class QuickActionsManager { quickActions.setShortcutItems([ ShortcutItem( type: 'add_note', - localizedTitle: AppLocalizations.of(context)!.action_add_note, - icon: 'launcher_icon', + localizedTitle: actionAddNoteTitle, + icon: 'ic_launcher', ), ]); } diff --git a/lib/utils/theme_manager.dart b/lib/utils/theme_manager.dart index 8d8ebb44..e6816dc1 100644 --- a/lib/utils/theme_manager.dart +++ b/lib/utils/theme_manager.dart @@ -86,7 +86,9 @@ class ThemeManager { } void setThemeMode(ThemeMode? themeMode) { - if (themeMode == null) return; + if (themeMode == null) { + return; + } int value; switch (themeMode) { diff --git a/pubspec.lock b/pubspec.lock index 73f97663..c548049b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "61.0.0" + after_layout: + dependency: "direct main" + description: + name: after_layout + sha256: "95a1cb2ca1464f44f14769329fbf15987d20ab6c88f8fc5d359bd362be625f29" + url: "https://pub.dev" + source: hosted + version: "1.2.0" analyzer: dependency: transitive description: @@ -101,10 +109,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.9" build_runner_core: dependency: transitive description: @@ -125,10 +133,10 @@ packages: dependency: transitive description: name: built_value - sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.9.0" + version: "8.9.2" characters: dependency: transitive description: @@ -197,10 +205,10 @@ packages: dependency: transitive description: name: cross_file - sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" url: "https://pub.dev" source: hosted - version: "0.3.3+8" + version: "0.3.4+1" crypto: dependency: transitive description: @@ -269,10 +277,10 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: "77f757b789ff68e4eaf9c56d1752309bd9f7ad557cb105b938a7f8eb89e59110" + sha256: "50fb435ed30c6d2525cbfaaa0f46851ea6131315f213c0d921b0e407b34e3b84" url: "https://pub.dev" source: hosted - version: "9.1.2" + version: "10.0.1" device_info_plus_platform_interface: dependency: transitive description: @@ -293,10 +301,10 @@ packages: dependency: "direct main" description: name: dynamic_color - sha256: a866f1f8947bfdaf674d7928e769eac7230388a2e7a2542824fad4bb5b87be3b + sha256: eae98052fa6e2826bdac3dd2e921c6ce2903be15c6b7f8b6d8a5d49b5086298d url: "https://pub.dev" source: hosted - version: "1.6.9" + version: "1.7.0" equatable: dependency: "direct main" description: @@ -317,10 +325,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -341,10 +349,10 @@ packages: dependency: "direct main" description: name: fleather - sha256: dbff159100d700a7f27fbcc97ffb5a0bcbf4aed3e6aa932b48133aa4040fb79b + sha256: "8684d0f403b851b68f96f45100fdc7e86660d62fb5b487a24d9a54ae2718bfaa" url: "https://pub.dev" source: hosted - version: "1.14.2" + version: "1.14.3" flutter: dependency: "direct main" description: flutter @@ -361,10 +369,11 @@ packages: flutter_launcher_icons: dependency: "direct dev" description: - name: flutter_launcher_icons - sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" - url: "https://pub.dev" - source: hosted + path: "." + ref: master + resolved-ref: "006cb1ed53f969bf11816cde5b16dd520e1ee40e" + url: "https://github.com/fluttercommunity/flutter_launcher_icons" + source: git version: "0.13.1" flutter_localizations: dependency: "direct main" @@ -375,26 +384,26 @@ packages: dependency: "direct main" description: name: flutter_native_splash - sha256: "558f10070f03ee71f850a78f7136ab239a67636a294a44a06b6b7345178edb1e" + sha256: edf39bcf4d74aca1eb2c1e43c3e445fd9f494013df7f0da752fefe72020eedc0 url: "https://pub.dev" source: hosted - version: "2.3.10" + version: "2.4.0" flutter_riverpod: dependency: "direct main" description: name: flutter_riverpod - sha256: "4bce556b7ecbfea26109638d5237684538d4abc509d253e6c5c4c5733b360098" + sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d" url: "https://pub.dev" source: hosted - version: "2.4.10" + version: "2.5.1" flutter_settings_ui: dependency: "direct main" description: name: flutter_settings_ui - sha256: aa371acae2f99b3348bf4e1a155f715dc146ac4cd410834f5bc44c3c12955a10 + sha256: dcc506fab724192594e5c232b6214a941abd6e7b5151626635b89258fadbc17c url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -417,10 +426,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -433,10 +442,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "07ee2436909f749d606f53521dc1725dd738dc5196e5ff815bc254253c594075" + sha256: "5ed2687bc961f33a752017ccaa7edead3e5601b28b6376a5901bf24728556b85" url: "https://pub.dev" source: hosted - version: "13.1.0" + version: "13.2.2" graphs: dependency: transitive description: @@ -449,10 +458,10 @@ packages: dependency: transitive description: name: hotreloader - sha256: "94ee21a60ea2836500799f3af035dc3212b1562027f1e0031c14e087f0231449" + sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "4.2.0" html: dependency: transitive description: @@ -465,10 +474,10 @@ packages: dependency: transitive description: name: http - sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" http_multi_server: dependency: transitive description: @@ -489,10 +498,10 @@ packages: dependency: transitive description: name: image - sha256: "49a0d4b0c12402853d3f227fe7c315601b238d126aa4caa5dbb2dcf99421aa4a" + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" url: "https://pub.dev" source: hosted - version: "4.1.6" + version: "4.1.7" intl: dependency: "direct main" description: @@ -657,10 +666,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79" + sha256: cb44f49b6e690fa766f023d5b22cac6b9affe741dd792b6ac7ad4fabe0d7b097 url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "6.0.0" package_info_plus_platform_interface: dependency: transitive description: @@ -841,10 +850,10 @@ packages: dependency: "direct main" description: name: receive_sharing_intent - sha256: "8fdf5927934041264becf65199ef8057b8b176e879d95ffa0420cd2a6219c0fd" + sha256: fcf167ad5aed85937c42d985dc31c7e50dbb3cf97dc5063a2bcfd26147023b34 url: "https://pub.dev" source: hosted - version: "1.6.7" + version: "1.6.8" restart_app: dependency: "direct main" description: @@ -857,10 +866,10 @@ packages: dependency: transitive description: name: riverpod - sha256: "548e2192eb7aeb826eb89387f814edb76594f3363e2c0bb99dd733d795ba3589" + sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.5.1" riverpod_analyzer_utils: dependency: transitive description: @@ -873,10 +882,10 @@ packages: dependency: "direct main" description: name: riverpod_annotation - sha256: "77e5d51afa4fa3e67903fb8746f33d368728d7051a0b6c292bcee60aeba46d95" + sha256: e5e796c0eba4030c704e9dae1b834a6541814963292839dcf9638d53eba84f5c url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" riverpod_generator: dependency: "direct dev" description: @@ -905,18 +914,18 @@ packages: dependency: "direct main" description: name: share_plus - sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900" + sha256: "05ec043470319bfbabe0adbc90d3a84cbff0426b9d9f3a6e2ad3e131fa5fa629" url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "8.0.2" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956 + sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.0" shared_preferences: dependency: "direct main" description: @@ -961,10 +970,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.3.0" shared_preferences_windows: dependency: transitive description: @@ -1134,26 +1143,26 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + sha256: "0ecc004c62fd3ed36a2ffcbe0dd9700aee63bd7532d0b642a488b1ec310f492e" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.2.5" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" + sha256: d4ed0711849dd8e33eb2dd69c25db0d0d3fdc37e0a62e629fe32f57a22db2745 url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.3.0" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5" url: "https://pub.dev" source: hosted - version: "6.2.4" + version: "6.2.5" url_launcher_linux: dependency: transitive description: @@ -1174,18 +1183,18 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.0" url_launcher_windows: dependency: transitive description: @@ -1230,26 +1239,26 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.4" win32: dependency: transitive description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: "0a989dc7ca2bb51eac91e8fd00851297cfffd641aa7538b165c62637ca0eaa4a" url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.4.0" win32_registry: dependency: transitive description: @@ -1291,5 +1300,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.3.1 <4.0.0" + flutter: ">=3.19.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3403a6fd..c4f9f604 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,52 +3,57 @@ description: Simple, local, material design notes repository: https://github.com/maelchiotti/LocalMaterialNotes documentation: https://github.com/maelchiotti/LocalMaterialNotes/wiki -version: 1.1.2+5 +version: 1.2.0+6 publish_to: none environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ">=3.3.1 <4.0.0" dependencies: + after_layout: ^1.2.0 collection: ^1.18.0 cupertino_icons: ^1.0.6 - device_info_plus: ^9.1.2 - dynamic_color: ^1.6.9 + device_info_plus: ^10.0.1 + dynamic_color: ^1.7.0 equatable: ^2.0.5 - fleather: ^1.14.2 + fleather: ^1.14.3 flutter: sdk: flutter flutter_hooks: ^0.20.5 flutter_localizations: sdk: flutter - flutter_native_splash: ^2.3.10 - flutter_riverpod: ^2.4.10 - flutter_settings_ui: ^3.0.0 - go_router: ^13.1.0 + flutter_native_splash: ^2.4.0 + flutter_riverpod: ^2.5.1 + flutter_settings_ui: ^3.0.1 + go_router: ^13.2.2 intl: ^0.18.1 is_first_run: ^1.0.0 isar: ^3.1.0+1 isar_flutter_libs: ^3.1.0+1 json_annotation: ^4.8.1 locale_names: ^1.1.1 - package_info_plus: ^5.0.1 - path: ^1.8.3 + package_info_plus: ^6.0.0 + path: ^1.9.0 path_provider: ^2.1.2 quick_actions: ^1.0.7 - receive_sharing_intent: ^1.6.7 + receive_sharing_intent: ^1.6.8 restart_app: ^1.2.1 - riverpod_annotation: ^2.3.4 - share_plus: ^7.2.2 + riverpod_annotation: ^2.3.5 + share_plus: ^8.0.2 shared_preferences: ^2.2.2 shared_storage: ^0.8.1 simple_icons: ^10.1.3 - url_launcher: ^6.2.4 + url_launcher: ^6.2.5 uuid: ^4.3.3 dev_dependencies: - build_runner: ^2.4.8 + build_runner: ^2.4.9 custom_lint: ^0.5.11 - flutter_launcher_icons: ^0.13.1 + # TODO: replace when the monochrome feature is released on pub.dev + flutter_launcher_icons: + git: + url: https://github.com/fluttercommunity/flutter_launcher_icons + ref: master flutter_test: sdk: flutter isar_generator: ^3.1.0+1