Refactor note handling to include ID generation and improve initialization logic
This commit is contained in:
@@ -66,7 +66,8 @@ Future<void> runPrimaryInstance(File ipcFile) async {
|
|||||||
startIpcWatcher(ipcFile);
|
startIpcWatcher(ipcFile);
|
||||||
|
|
||||||
// Initialize the app
|
// Initialize the app
|
||||||
await DB.init();
|
// await DB.init();
|
||||||
|
await init();
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
|
|
||||||
WindowOptions windowOptions = const WindowOptions(
|
WindowOptions windowOptions = const WindowOptions(
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
import 'dart:math';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:journaler/notes.dart';
|
import 'package:journaler/notes.dart';
|
||||||
|
|
||||||
@@ -7,7 +8,15 @@ const endpoint = 'https://meili.site.quack-lab.dev/';
|
|||||||
const noteIndex = 'notes';
|
const noteIndex = 'notes';
|
||||||
const scratchIndex = 'scratch';
|
const scratchIndex = 'scratch';
|
||||||
const settingsIndex = 'settings';
|
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 {
|
class MeilisearchQuery {
|
||||||
String q;
|
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
|
// Settings Management
|
||||||
Future<String?> getSetting(String key) async {
|
Future<String?> getSetting(String key) async {
|
||||||
final searchCondition = MeilisearchQuery(q: '', filter: 'key = $key');
|
final searchCondition = MeilisearchQuery(q: '', filter: 'key = $key');
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$settingsIndex/search'),
|
Uri.parse('$endpoint/indexes/$settingsIndex/search'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(searchCondition.toJson()),
|
body: jsonEncode(searchCondition.toJson()),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -104,7 +161,7 @@ Future<void> setSetting(String key, String value) async {
|
|||||||
final document = {'key': key, 'value': value};
|
final document = {'key': key, 'value': value};
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$settingsIndex/documents'),
|
Uri.parse('$endpoint/indexes/$settingsIndex/documents'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(document),
|
body: jsonEncode(document),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -125,7 +182,7 @@ Future<List<Note>> searchNotes(String query) async {
|
|||||||
);
|
);
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(searchCondition.toJson()),
|
body: jsonEncode(searchCondition.toJson()),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -135,6 +192,7 @@ Future<List<Note>> searchNotes(String query) async {
|
|||||||
return responseJson.hits
|
return responseJson.hits
|
||||||
.map(
|
.map(
|
||||||
(hit) => Note(
|
(hit) => Note(
|
||||||
|
id: hit['id'] as String,
|
||||||
date: hit['date'] as String,
|
date: hit['date'] as String,
|
||||||
content: hit['content'] as String,
|
content: hit['content'] as String,
|
||||||
),
|
),
|
||||||
@@ -151,7 +209,7 @@ Future<Note?> getPreviousTo(String date) async {
|
|||||||
);
|
);
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(searchCondition.toJson()),
|
body: jsonEncode(searchCondition.toJson()),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -162,6 +220,7 @@ Future<Note?> getPreviousTo(String date) async {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Note(
|
return Note(
|
||||||
|
id: responseJson.hits.first['id'] as String,
|
||||||
date: responseJson.hits.first['date'] as String,
|
date: responseJson.hits.first['date'] as String,
|
||||||
content: responseJson.hits.first['content'] as String,
|
content: responseJson.hits.first['content'] as String,
|
||||||
);
|
);
|
||||||
@@ -176,7 +235,7 @@ Future<Note?> getNextTo(String date) async {
|
|||||||
);
|
);
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(searchCondition.toJson()),
|
body: jsonEncode(searchCondition.toJson()),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -187,6 +246,7 @@ Future<Note?> getNextTo(String date) async {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Note(
|
return Note(
|
||||||
|
id: responseJson.hits.first['id'] as String,
|
||||||
date: responseJson.hits.first['date'] as String,
|
date: responseJson.hits.first['date'] as String,
|
||||||
content: responseJson.hits.first['content'] as String,
|
content: responseJson.hits.first['content'] as String,
|
||||||
);
|
);
|
||||||
@@ -195,12 +255,12 @@ Future<Note?> getNextTo(String date) async {
|
|||||||
Future<Note?> getLatest() async {
|
Future<Note?> getLatest() async {
|
||||||
final searchCondition = MeilisearchQuery(
|
final searchCondition = MeilisearchQuery(
|
||||||
q: '',
|
q: '',
|
||||||
sort: ['date DESC'],
|
sort: ['date:desc'],
|
||||||
limit: 1,
|
limit: 1,
|
||||||
);
|
);
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(searchCondition.toJson()),
|
body: jsonEncode(searchCondition.toJson()),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -211,11 +271,23 @@ Future<Note?> getLatest() async {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Note(
|
return Note(
|
||||||
|
id: responseJson.hits.first['id'] as String,
|
||||||
date: responseJson.hits.first['date'] as String,
|
date: responseJson.hits.first['date'] as String,
|
||||||
content: responseJson.hits.first['content'] 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 {
|
Future<Note> createNote(String content) async {
|
||||||
final lines = content.split('\n');
|
final lines = content.split('\n');
|
||||||
final trimmedLines = <String>[];
|
final trimmedLines = <String>[];
|
||||||
@@ -238,20 +310,22 @@ Future<Note> createNote(String content) async {
|
|||||||
final mostFrequentLetterCount = letterFrequency[mostFrequentLetter];
|
final mostFrequentLetterCount = letterFrequency[mostFrequentLetter];
|
||||||
|
|
||||||
final document = {
|
final document = {
|
||||||
'id': DateTime.now().toIso8601String(),
|
'id': generateRandomString(32),
|
||||||
|
'date': DateTime.now().toIso8601String(),
|
||||||
'content': content,
|
'content': content,
|
||||||
'topLetter': mostFrequentLetter,
|
'topLetter': mostFrequentLetter,
|
||||||
'topLetterFrequency': mostFrequentLetterCount,
|
'topLetterFrequency': mostFrequentLetterCount,
|
||||||
};
|
};
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$noteIndex/documents'),
|
Uri.parse('$endpoint/indexes/$noteIndex/documents'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(document),
|
body: jsonEncode(document),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
throw Exception('Failed to create note');
|
throw Exception('Failed to create note');
|
||||||
}
|
}
|
||||||
return Note(
|
return Note(
|
||||||
|
id: document['id'] as String,
|
||||||
date: document['id'] as String,
|
date: document['id'] as String,
|
||||||
content: document['content'] 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(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
Uri.parse('$endpoint/indexes/$noteIndex/search'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(searchCondition.toJson()),
|
body: jsonEncode(searchCondition.toJson()),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -274,6 +348,7 @@ Future<List<Note>> getProblematic({double threshold = 0.7}) async {
|
|||||||
return responseJson.hits
|
return responseJson.hits
|
||||||
.map(
|
.map(
|
||||||
(hit) => Note(
|
(hit) => Note(
|
||||||
|
id: hit['id'] as String,
|
||||||
date: hit['date'] as String,
|
date: hit['date'] as String,
|
||||||
content: hit['content'] as String,
|
content: hit['content'] as String,
|
||||||
isProblematic: true,
|
isProblematic: true,
|
||||||
@@ -285,10 +360,11 @@ Future<List<Note>> getProblematic({double threshold = 0.7}) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateNote(String id, String content) async {
|
Future<void> updateNote(String id, String content) async {
|
||||||
|
// TODO: Trim and calculate frequency
|
||||||
final document = {'id': id, 'content': content};
|
final document = {'id': id, 'content': content};
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$noteIndex/documents'),
|
Uri.parse('$endpoint/indexes/$noteIndex/documents'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(document),
|
body: jsonEncode(document),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -299,7 +375,7 @@ Future<void> updateNote(String id, String content) async {
|
|||||||
Future<void> deleteNote(String id) async {
|
Future<void> deleteNote(String id) async {
|
||||||
final response = await http.delete(
|
final response = await http.delete(
|
||||||
Uri.parse('$endpoint/indexes/$noteIndex/documents/$id'),
|
Uri.parse('$endpoint/indexes/$noteIndex/documents/$id'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
throw Exception('Failed to delete note');
|
throw Exception('Failed to delete note');
|
||||||
@@ -314,7 +390,7 @@ Future<Scratch?> getLatestScratch() async {
|
|||||||
);
|
);
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$scratchIndex/search'),
|
Uri.parse('$endpoint/indexes/$scratchIndex/search'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(searchCondition.toJson()),
|
body: jsonEncode(searchCondition.toJson()),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
@@ -334,7 +410,7 @@ Future<void> createScratch(String content) async {
|
|||||||
final document = {'id': DateTime.now().toIso8601String(), 'content': content};
|
final document = {'id': DateTime.now().toIso8601String(), 'content': content};
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$endpoint/indexes/$scratchIndex/documents'),
|
Uri.parse('$endpoint/indexes/$scratchIndex/documents'),
|
||||||
headers: {'Authorization': 'Bearer $apiKey'},
|
headers: header,
|
||||||
body: jsonEncode(document),
|
body: jsonEncode(document),
|
||||||
);
|
);
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class Note {
|
class Note {
|
||||||
|
final String id;
|
||||||
final String date;
|
final String date;
|
||||||
late final String displayDate;
|
late final String displayDate;
|
||||||
String content;
|
String content;
|
||||||
@@ -9,6 +10,7 @@ class Note {
|
|||||||
String problemReason;
|
String problemReason;
|
||||||
|
|
||||||
Note({
|
Note({
|
||||||
|
required this.id,
|
||||||
required this.date,
|
required this.date,
|
||||||
required this.content,
|
required this.content,
|
||||||
this.snippet,
|
this.snippet,
|
||||||
|
Reference in New Issue
Block a user