Refactor note handling to include ID generation and improve initialization logic

This commit is contained in:
2025-05-23 22:40:19 +02:00
parent 89f8889f1e
commit dfe1c2b34c
3 changed files with 95 additions and 16 deletions

View File

@@ -66,7 +66,8 @@ Future<void> runPrimaryInstance(File ipcFile) async {
startIpcWatcher(ipcFile);
// Initialize the app
await DB.init();
// await DB.init();
await init();
await windowManager.ensureInitialized();
WindowOptions windowOptions = const WindowOptions(

View File

@@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:core';
import 'dart:math';
import 'package:http/http.dart' as http;
import 'package:journaler/notes.dart';
@@ -7,7 +8,15 @@ const endpoint = 'https://meili.site.quack-lab.dev/';
const noteIndex = 'notes';
const scratchIndex = 'scratch';
const settingsIndex = 'settings';
const apiKey = String.fromEnvironment('MEILISEARCH_API_KEY', defaultValue: '');
const apiKey = String.fromEnvironment(
'MEILISEARCH_API_KEY',
defaultValue:
'',
);
const header = {
'Authorization': 'Bearer $apiKey',
'Content-Type': 'application/json',
};
class MeilisearchQuery {
String q;
@@ -82,12 +91,60 @@ class MeilisearchResponse {
}
}
Future<void> init() async {
if (!await indexExists(noteIndex)) {
await http.post(
Uri.parse('$endpoint/indexes'),
headers: header,
body: jsonEncode({'uid': noteIndex, 'primaryKey': 'id'}),
);
await http.put(
Uri.parse('$endpoint/indexes/$noteIndex/settings/sortable-attributes'),
headers: header,
body: jsonEncode({
'attributes': ['date'],
}),
);
}
if (!await indexExists(scratchIndex)) {
await http.post(
Uri.parse('$endpoint/indexes'),
headers: header,
body: jsonEncode({'uid': scratchIndex, 'primaryKey': 'id'}),
);
await http.put(
Uri.parse('$endpoint/indexes/$scratchIndex/settings/sortable-attributes'),
headers: header,
body: jsonEncode({
'attributes': ['date'],
}),
);
}
if (!await indexExists(settingsIndex)) {
await http.post(
Uri.parse('$endpoint/indexes'),
headers: header,
body: jsonEncode({'uid': settingsIndex, 'primaryKey': 'key'}),
);
}
}
Future<bool> indexExists(String index) async {
final response = await http.get(
Uri.parse('$endpoint/indexes/$index'),
headers: header,
);
return response.statusCode == 200;
}
// Settings Management
Future<String?> getSetting(String key) async {
final searchCondition = MeilisearchQuery(q: '', filter: 'key = $key');
final response = await http.post(
Uri.parse('$endpoint/indexes/$settingsIndex/search'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(searchCondition.toJson()),
);
if (response.statusCode != 200) {
@@ -104,7 +161,7 @@ Future<void> setSetting(String key, String value) async {
final document = {'key': key, 'value': value};
final response = await http.post(
Uri.parse('$endpoint/indexes/$settingsIndex/documents'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(document),
);
if (response.statusCode != 200) {
@@ -125,7 +182,7 @@ Future<List<Note>> searchNotes(String query) async {
);
final response = await http.post(
Uri.parse('$endpoint/indexes/$noteIndex/search'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(searchCondition.toJson()),
);
if (response.statusCode != 200) {
@@ -135,6 +192,7 @@ Future<List<Note>> searchNotes(String query) async {
return responseJson.hits
.map(
(hit) => Note(
id: hit['id'] as String,
date: hit['date'] as String,
content: hit['content'] as String,
),
@@ -151,7 +209,7 @@ Future<Note?> getPreviousTo(String date) async {
);
final response = await http.post(
Uri.parse('$endpoint/indexes/$noteIndex/search'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(searchCondition.toJson()),
);
if (response.statusCode != 200) {
@@ -162,6 +220,7 @@ Future<Note?> getPreviousTo(String date) async {
return null;
}
return Note(
id: responseJson.hits.first['id'] as String,
date: responseJson.hits.first['date'] as String,
content: responseJson.hits.first['content'] as String,
);
@@ -176,7 +235,7 @@ Future<Note?> getNextTo(String date) async {
);
final response = await http.post(
Uri.parse('$endpoint/indexes/$noteIndex/search'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(searchCondition.toJson()),
);
if (response.statusCode != 200) {
@@ -187,6 +246,7 @@ Future<Note?> getNextTo(String date) async {
return null;
}
return Note(
id: responseJson.hits.first['id'] as String,
date: responseJson.hits.first['date'] as String,
content: responseJson.hits.first['content'] as String,
);
@@ -195,12 +255,12 @@ Future<Note?> getNextTo(String date) async {
Future<Note?> getLatest() async {
final searchCondition = MeilisearchQuery(
q: '',
sort: ['date DESC'],
sort: ['date:desc'],
limit: 1,
);
final response = await http.post(
Uri.parse('$endpoint/indexes/$noteIndex/search'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(searchCondition.toJson()),
);
if (response.statusCode != 200) {
@@ -211,11 +271,23 @@ Future<Note?> getLatest() async {
return null;
}
return Note(
id: responseJson.hits.first['id'] as String,
date: responseJson.hits.first['date'] as String,
content: responseJson.hits.first['content'] as String,
);
}
String generateRandomString(int length) {
const characters =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var result = '';
for (var i = 0; i < length; i++) {
final randomIndex = Random().nextInt(characters.length);
result += characters[randomIndex];
}
return result;
}
Future<Note> createNote(String content) async {
final lines = content.split('\n');
final trimmedLines = <String>[];
@@ -238,20 +310,22 @@ Future<Note> createNote(String content) async {
final mostFrequentLetterCount = letterFrequency[mostFrequentLetter];
final document = {
'id': DateTime.now().toIso8601String(),
'id': generateRandomString(32),
'date': DateTime.now().toIso8601String(),
'content': content,
'topLetter': mostFrequentLetter,
'topLetterFrequency': mostFrequentLetterCount,
};
final response = await http.post(
Uri.parse('$endpoint/indexes/$noteIndex/documents'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(document),
);
if (response.statusCode != 200) {
throw Exception('Failed to create note');
}
return Note(
id: document['id'] as String,
date: document['id'] as String,
content: document['content'] as String,
);
@@ -264,7 +338,7 @@ Future<List<Note>> getProblematic({double threshold = 0.7}) async {
);
final response = await http.post(
Uri.parse('$endpoint/indexes/$noteIndex/search'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(searchCondition.toJson()),
);
if (response.statusCode != 200) {
@@ -274,6 +348,7 @@ Future<List<Note>> getProblematic({double threshold = 0.7}) async {
return responseJson.hits
.map(
(hit) => Note(
id: hit['id'] as String,
date: hit['date'] as String,
content: hit['content'] as String,
isProblematic: true,
@@ -285,10 +360,11 @@ Future<List<Note>> getProblematic({double threshold = 0.7}) async {
}
Future<void> updateNote(String id, String content) async {
// TODO: Trim and calculate frequency
final document = {'id': id, 'content': content};
final response = await http.post(
Uri.parse('$endpoint/indexes/$noteIndex/documents'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(document),
);
if (response.statusCode != 200) {
@@ -299,7 +375,7 @@ Future<void> updateNote(String id, String content) async {
Future<void> deleteNote(String id) async {
final response = await http.delete(
Uri.parse('$endpoint/indexes/$noteIndex/documents/$id'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
);
if (response.statusCode != 200) {
throw Exception('Failed to delete note');
@@ -314,7 +390,7 @@ Future<Scratch?> getLatestScratch() async {
);
final response = await http.post(
Uri.parse('$endpoint/indexes/$scratchIndex/search'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(searchCondition.toJson()),
);
if (response.statusCode != 200) {
@@ -334,7 +410,7 @@ Future<void> createScratch(String content) async {
final document = {'id': DateTime.now().toIso8601String(), 'content': content};
final response = await http.post(
Uri.parse('$endpoint/indexes/$scratchIndex/documents'),
headers: {'Authorization': 'Bearer $apiKey'},
headers: header,
body: jsonEncode(document),
);
if (response.statusCode != 200) {

View File

@@ -1,6 +1,7 @@
import 'package:intl/intl.dart';
class Note {
final String id;
final String date;
late final String displayDate;
String content;
@@ -9,6 +10,7 @@ class Note {
String problemReason;
Note({
required this.id,
required this.date,
required this.content,
this.snippet,