Skip to content

Commit

Permalink
Fixes (#19)
Browse files Browse the repository at this point in the history
* feat: improve error handling and snackbar messages for export and import

* fix: add note action crashing when the current route was not the notes list and when app was closed

* fix: remove useless editor FocusNode

* fix: action of quick action

* fix: remove prints
  • Loading branch information
maelchiotti authored Apr 4, 2024
1 parent 01edef3 commit 17f04c7
Show file tree
Hide file tree
Showing 14 changed files with 86 additions and 105 deletions.
9 changes: 8 additions & 1 deletion lib/app.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
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';
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';

Expand All @@ -15,7 +17,7 @@ class App extends ConsumerStatefulWidget {
ConsumerState<App> createState() => _AppState();
}

class _AppState extends ConsumerState<App> {
class _AppState extends ConsumerState<App> with AfterLayoutMixin<App> {
late StreamSubscription _stream;

@override
Expand All @@ -26,6 +28,11 @@ class _AppState extends ConsumerState<App> {
_stream = listenSharedData(ref);
}

@override
void afterFirstLayout(BuildContext context) {
QuickActionsManager().init(navigatorKey.currentContext!, ref);
}

@override
void dispose() {
_stream.cancel();
Expand Down
7 changes: 3 additions & 4 deletions lib/common/actions/add.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'package:localmaterialnotes/models/note/note.dart';
import 'package:localmaterialnotes/providers/current_note/current_note_provider.dart';

Future<void> addNote(BuildContext context, WidgetRef ref, {String? content}) async {
unselectAll(ref);
exitSelectionMode(ref);

final note = content == null ? Note.empty() : Note.content(content);
Expand All @@ -17,11 +16,11 @@ Future<void> addNote(BuildContext context, WidgetRef ref, {String? content}) asy

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);
}
3 changes: 0 additions & 3 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,16 @@
"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",
"settings_licence": "License",
"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",
Expand Down
5 changes: 1 addition & 4 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,16 @@
"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",
Expand Down
18 changes: 0 additions & 18 deletions lib/l10n/app_localizations.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -264,12 +264,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:
Expand All @@ -288,12 +282,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:
Expand Down Expand Up @@ -336,12 +324,6 @@ 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:
Expand Down
13 changes: 0 additions & 13 deletions lib/l10n/app_localizations_en.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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';

Expand All @@ -135,9 +125,6 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get settings_issue_description => 'Report a bug by creating an issue on GitHub';

@override
String get action_add_note => 'Add a note';

@override
String get hint_title => 'Title';

Expand Down
13 changes: 0 additions & 13 deletions lib/l10n/app_localizations_fr.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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';

Expand All @@ -137,9 +127,6 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get settings_issue_description => 'Signaler un bug en créant une issue sur GitHub';

@override
String get action_add_note => 'Ajouter une note';

@override
String get hint_title => 'Titre';

Expand Down
2 changes: 0 additions & 2 deletions lib/pages/editor/editor_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class EditorPage extends ConsumerStatefulWidget {
class _EditorState extends ConsumerState<EditorPage> {
final titleController = TextEditingController();
late FleatherController fleatherController;
final fleatherFocusNode = FocusNode();

void _synchronizeTitle(Note note, String? newTitle) {
if (newTitle == null) return;
Expand Down Expand Up @@ -81,7 +80,6 @@ class _EditorState extends ConsumerState<EditorPage> {
Expanded(
child: FleatherField(
controller: fleatherController,
focusNode: fleatherFocusNode,
autofocus: widget._autofocus,
readOnly: widget._readOnly,
expands: true,
Expand Down
3 changes: 0 additions & 3 deletions lib/pages/notes/notes_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -21,8 +20,6 @@ class NotesPage extends ConsumerStatefulWidget {
class _NotesPageState extends ConsumerState<NotesPage> {
@override
Widget build(BuildContext context) {
QuickActionsManager().init(context, ref);

return ref.watch(notesProvider).when(
data: (notes) {
if (notes.isEmpty) return EmptyPlaceholder.notes();
Expand Down
30 changes: 15 additions & 15 deletions lib/pages/settings/interactions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,38 +126,38 @@ class Interactions {

Future<void> 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<void> 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<void> 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<void> showAbout(BuildContext context) async {
Expand Down
20 changes: 12 additions & 8 deletions lib/utils/database_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,28 +88,28 @@ class DatabaseManager {
});
}

Future<void> exportAsJson() async {
Future<bool> exportAsJson() async {
final notes = await getAll();
final notesAsJson = jsonEncode(notes);

await _export('application/json', 'json', notesAsJson);
return await _export('application/json', 'json', notesAsJson);
}

Future<void> exportAsMarkdown() async {
Future<bool> exportAsMarkdown() async {
final notes = await getAll();
final StringBuffer notesAsMarkdown = StringBuffer('# Material Notes\n\n');
for (final note in notes) {
notesAsMarkdown
.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<void> _export(String mimeType, String extension, String notesAsString) async {
Future<bool> _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();

Expand All @@ -119,15 +119,17 @@ class DatabaseManager {
displayName: 'materialnotes_export_${timestamp.filename}.$extension',
bytes: Uint8List.fromList(utf8.encode(notesAsString)),
);

return true;
}

Future<void> import() async {
Future<bool> 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);

Expand All @@ -138,6 +140,8 @@ class DatabaseManager {
final notes = notesJson.map((e) => Note.fromJson(e as Map<String, dynamic>)).toList();

await addAll(notes);

return true;
}

/// Hardcode the welcome note translations here because no context is available when it's used
Expand Down
23 changes: 20 additions & 3 deletions lib/utils/quick_actions_manager.dart
Original file line number Diff line number Diff line change
@@ -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/utils/locale_manager.dart';
import 'package:quick_actions/quick_actions.dart';

class QuickActionsManager {
Expand All @@ -19,9 +19,26 @@ class QuickActionsManager {
quickActions.setShortcutItems([
ShortcutItem(
type: 'add_note',
localizedTitle: AppLocalizations.of(context)!.action_add_note,
icon: 'launcher_icon',
localizedTitle: _actionAddNoteTitle,
icon: 'ic_launcher',
),
]);
}

/// Hardcode the action title translations here because no context is available when it's used
String get _actionAddNoteTitle {
final locale = LocaleManager().locale;

final String title;

if (locale == const Locale('en')) {
title = 'Add a note';
} else if (locale == const Locale('fr')) {
title = 'Ajouter une note';
} else {
throw Exception('Missing title of add note action for locale: $locale');
}

return title;
}
}
Loading

0 comments on commit 17f04c7

Please sign in to comment.