diff --git a/lib/common/preferences/preference_key.dart b/lib/common/preferences/preference_key.dart index b6699507..8ed69bba 100644 --- a/lib/common/preferences/preference_key.dart +++ b/lib/common/preferences/preference_key.dart @@ -117,9 +117,6 @@ enum PreferenceKey { /// Returns the value of this preference if set, or its default value otherwise. T get preferenceOrDefault => PreferencesWrapper().get(this) ?? defaultValue; - /// Returns the value of this securely stored preference if set, or [null] otherwise. - T? get preferenceSecure => PreferencesWrapper().get(this); - /// Returns the value of this securely stored preference if set, or its default value otherwise. Future get preferenceOrDefaultSecure async => await PreferencesWrapper().getSecure(this) ?? defaultValue as String; diff --git a/lib/l10n/translations/app_en.arb b/lib/l10n/translations/app_en.arb index 5708e0c0..65e2885e 100644 --- a/lib/l10n/translations/app_en.arb +++ b/lib/l10n/translations/app_en.arb @@ -547,7 +547,7 @@ "@settings_auto_export_frequency": { "description": "Title of the settings tile to choose the frequency of the automatic exports." }, - "settings_auto_export_frequency_value": "Every {frequency, select, 1{day} 7{week} 14{2 weeks} 30{month} other{}}", + "settings_auto_export_frequency_value": "Every {frequency, select, 1{day} 3{3 days} 7{week} 14{2 weeks} 30{month} other{}}", "@settings_auto_export_frequency_value": { "description": "Frequency of the automatic exports.", "placeholders": { diff --git a/lib/models/note/note.dart b/lib/models/note/note.dart index 8da8d2f6..d6d7a9e9 100644 --- a/lib/models/note/note.dart +++ b/lib/models/note/note.dart @@ -210,7 +210,9 @@ sealed class Note implements Comparable { case SortMethod.editedDate: return sortAscending ? editedTime.compareTo(other.editedTime) : other.editedTime.compareTo(editedTime); case SortMethod.title: - return sortAscending ? title.compareTo(other.title) : other.title.compareTo(title); + final titleComparison = title.toLowerCase().compareTo(other.title.toLowerCase()); + + return sortAscending ? titleComparison : -titleComparison; default: throw Exception('The sort method is not valid: $sortMethod'); } diff --git a/lib/services/migration/migration_service.dart b/lib/services/migration/migration_service.dart index ac2e9859..b3730075 100644 --- a/lib/services/migration/migration_service.dart +++ b/lib/services/migration/migration_service.dart @@ -3,14 +3,13 @@ import 'package:isar_community/isar.dart'; import '../../common/constants/constants.dart'; import '../../common/preferences/preference_key.dart'; import '../../models/deprecated/note.dart'; +import '../../models/label/label.dart'; import '../../models/note/note.dart'; import '../database_service.dart'; -import '../notes/notes_service.dart'; /// Database migration service. class MigrationService { final _databaseService = DatabaseService(); - final _notesService = NotesService(); /// Migrates the database to the latest version if needed. Future migrateIfNeeded() async { @@ -30,13 +29,12 @@ class MigrationService { /// Moves all legacy notes from the legacy `notes` collection to the new `richTextNotes` collection /// to allow adding different types of notes. Future _migrateToV2() async { + final database = _databaseService.database; + // Get the notes and their labels - final notes = await _databaseService.database.notes.where().findAll(); + final notes = await database.notes.where().findAll(); final labels = notes.map((note) => note.labels.toList()).toList(); - // Remove the notes - await _databaseService.database.notes.clear(); - // Migrate the notes final migratedNotes = notes .map( @@ -53,9 +51,12 @@ class MigrationService { ) .toList(); - // Add the migrated notes to the new collection with their labels - await _notesService.putAll(migratedNotes); - await _notesService.putAllLabels(migratedNotes, labels); + // Replace the notes by the migrated ones with their labels, all at once so that a failure loses nothing + await database.writeTxn(() async { + await database.notes.clear(); + await database.richTextNotes.putAll(migratedNotes); + await _putLabels(migratedNotes, labels); + }); // Update the database version await PreferenceKey.databaseVersion.set(2); @@ -67,11 +68,12 @@ class MigrationService { /// /// Sets the new `id`, `archived` and `deletedTime` fields of each rich text note. Future _migrateToV3() async { - // Get the rich text notes - final richTextNotes = await _databaseService.database.richTextNotes.where().findAll(); + final database = _databaseService.database; - // Remove the notes with the old IDs - await _notesService.deleteAll(richTextNotes); + // Get the rich text notes, their labels and their old IDs + final richTextNotes = await database.richTextNotes.where().findAll(); + final labels = richTextNotes.map((note) => note.labels.toList()).toList(); + final oldIds = richTextNotes.map((note) => note.isarId).toList(); // Migrate the notes final migratedNotes = richTextNotes @@ -83,12 +85,26 @@ class MigrationService { ) .toList(); - // Put back the migrated notes with the right IDs - await _notesService.putAll(migratedNotes); + // Replace the notes with the old IDs by the migrated ones with their labels, which are linked to the IDs, + // all at once so that a failure loses nothing + await database.writeTxn(() async { + await database.richTextNotes.deleteAll(oldIds); + await database.richTextNotes.putAll(migratedNotes); + await _putLabels(migratedNotes, labels); + }); // Update the database version await PreferenceKey.databaseVersion.set(3); logger.i('Migrated the database from version 2 to version 3'); } + + /// Links each of the [notes] to its [labels], inside a write transaction. + Future _putLabels(List notes, List> labels) async { + for (var i = 0; i < notes.length; i++) { + await notes[i].labels.reset(); + notes[i].labels.addAll(labels[i]); + await notes[i].labels.save(); + } + } } diff --git a/lib/services/notes/notes_service.dart b/lib/services/notes/notes_service.dart index 215652f6..4d1cac93 100644 --- a/lib/services/notes/notes_service.dart +++ b/lib/services/notes/notes_service.dart @@ -242,25 +242,6 @@ class NotesService { }); } - /// Updates the [notes] with their corresponding [notesLabels] in the database. - Future putAllLabels(List notes, List> notesLabels) async { - assert( - notes.length == notesLabels.length, - 'The list of labels (${notesLabels.length} items) should be the same length as the list of notes (${notes.length} notes)', - ); - - await _database.writeTxn(() async { - for (var i = 0; i < notes.length; i++) { - final note = notes[i]; - final labels = notesLabels[i]; - - await note.labels.reset(); - note.labels.addAll(labels); - await note.labels.save(); - } - }); - } - /// Imports the [labels] and the [notes] in a single transaction, so that a failure leaves the database untouched. /// /// Only the labels whose name is not in the database yet are added. Each note is linked to the labels