242 lines
6.5 KiB
Dart
242 lines
6.5 KiB
Dart
import 'package:appwrite/appwrite.dart';
|
|
import 'package:appwrite/models.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:ltx_flutter/appwrite/auth_api.dart';
|
|
import 'package:ltx_flutter/constants/constants.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
class DatabaseAPI extends ChangeNotifier {
|
|
Client client = Client();
|
|
late final Account account;
|
|
late final Databases databases;
|
|
late final Realtime realtime;
|
|
final AuthAPI auth = AuthAPI();
|
|
|
|
late List<Document> _entries = [];
|
|
bool _ready = false;
|
|
|
|
// Getter methods
|
|
List<Document> get entries => _entries;
|
|
int get length => _entries.length;
|
|
bool get ready => _ready;
|
|
double get progress => length / total();
|
|
|
|
final DateFormat formatter = DateFormat('yyyy-MM-dd');
|
|
|
|
// Constructor
|
|
DatabaseAPI() {
|
|
init();
|
|
getAll();
|
|
subscribeRealtime();
|
|
}
|
|
|
|
init() {
|
|
client.setEndpoint(APPWRITE_URL).setProject(APPWRITE_PROJECT_ID);
|
|
account = Account(client);
|
|
databases = Databases(client);
|
|
realtime = Realtime(client);
|
|
}
|
|
|
|
elDate(dynamic el) {
|
|
return formatter.format(DateTime.parse(el.data['date']));
|
|
}
|
|
|
|
sortByDate(entries) {
|
|
return entries.sort(
|
|
(a, b) => a.$id.compareTo(b.$id),
|
|
);
|
|
}
|
|
|
|
subscribeRealtime() {
|
|
final subscription = realtime.subscribe(
|
|
['databases.$APPWRITE_DATABASE_ID.collections.$COLLECTION.documents']);
|
|
|
|
print("Subscribed to realtime");
|
|
subscription.stream.listen((response) {
|
|
String dateISO =
|
|
formatter.format(DateTime.parse(response.payload['date']));
|
|
if (response.events.contains(
|
|
'databases.$APPWRITE_DATABASE_ID.collections.$COLLECTION.documents.*.update')) {
|
|
// Entry was updated
|
|
|
|
int entryIndex =
|
|
_entries.indexWhere((element) => elDate(element) == dateISO);
|
|
Document newEntry = _entries[entryIndex];
|
|
newEntry.data['hours'] = response.payload['hours'];
|
|
newEntry.data['mood'] = response.payload['mood'];
|
|
newEntry.data['comments'] = response.payload['comments'];
|
|
|
|
_entries.removeAt(entryIndex);
|
|
_entries.add(newEntry);
|
|
notifyListeners();
|
|
// _entries.add(entry);
|
|
// sortByDate(_entries);
|
|
|
|
}
|
|
});
|
|
}
|
|
|
|
int total() {
|
|
String dateISO = DateTime.now().toIso8601String();
|
|
|
|
var referenceDate = DateTime.parse("2023-01-01");
|
|
|
|
final date = DateTime.parse(dateISO);
|
|
|
|
int _total = date.difference(referenceDate).inDays + 1;
|
|
return _total;
|
|
}
|
|
|
|
getAll() async {
|
|
print("Loading entries");
|
|
|
|
String paginationQuery = Query.offset(0);
|
|
int max = total();
|
|
|
|
while (_entries.length < max) {
|
|
int remainder = max - _entries.length;
|
|
int limit = remainder > 100 ? 100 : remainder;
|
|
|
|
if (_entries.isNotEmpty) {
|
|
String lastDate = _entries.last.$id;
|
|
paginationQuery = Query.cursorAfter(lastDate);
|
|
}
|
|
|
|
List<Document> newEntries = await getEntries(
|
|
limit: limit,
|
|
paginationQuery: paginationQuery,
|
|
);
|
|
|
|
if(newEntries.isEmpty){
|
|
// This only happens if we were expecting more
|
|
// (i.e., _entries.length < max),
|
|
// but getEntries didn't return anything
|
|
// (i.e., an entry doesn't exist).
|
|
// So, let's create it.
|
|
//
|
|
// BAD CODE: THIS ASSUMES IT NEEDS TO BE TODAY
|
|
// This will eventually break.
|
|
//
|
|
|
|
Document new_today_entry = await getOne(date: formatter.format(DateTime.now()));
|
|
|
|
newEntries.add(new_today_entry);
|
|
}
|
|
|
|
_entries.addAll(newEntries);
|
|
notifyListeners();
|
|
}
|
|
_ready = true;
|
|
print("Got ${_entries.length} entries");
|
|
}
|
|
|
|
getOne({required String date}) async {
|
|
try {
|
|
// print(date);
|
|
// print(_entries.last.$id);
|
|
return _entries.singleWhere((element) => element.$id == date);
|
|
} catch (e) {
|
|
int offset =
|
|
DateTime.parse(date).difference(DateTime.parse("2023-01-01")).inDays +
|
|
1;
|
|
|
|
List<Document> response = await getEntries(
|
|
limit: 1,
|
|
paginationQuery: Query.offset(offset),
|
|
);
|
|
if(response.isEmpty){
|
|
print("No entry in database; creating $date");
|
|
Document newEntry = await addEntry(date: date);
|
|
_entries.add(newEntry);
|
|
notifyListeners();
|
|
return(newEntry);
|
|
}
|
|
else{
|
|
_entries.add(response.first);
|
|
notifyListeners();
|
|
return(response.first);
|
|
}
|
|
}
|
|
}
|
|
|
|
getEntries({int limit = 100, paginationQuery}) async {
|
|
var response = await databases.listDocuments(
|
|
databaseId: APPWRITE_DATABASE_ID,
|
|
collectionId: COLLECTION,
|
|
queries: [
|
|
Query.orderAsc("date"),
|
|
paginationQuery,
|
|
Query.limit(limit),
|
|
]);
|
|
return response.documents;
|
|
}
|
|
|
|
Future<Document> updateEntry(
|
|
{String? dateISO,
|
|
List<dynamic>? hours,
|
|
int? mood,
|
|
String? comments}) async {
|
|
String date = formatter.format(DateTime.parse(dateISO!));
|
|
|
|
int entryIndex = _entries.indexWhere((element) => elDate(element) == date);
|
|
|
|
hours ??= _entries[entryIndex].data['hours'];
|
|
comments ??= _entries[entryIndex].data['comments'];
|
|
mood ??= _entries[entryIndex].data['mood'];
|
|
|
|
Document newEntry = await databases.updateDocument(
|
|
databaseId: APPWRITE_DATABASE_ID,
|
|
collectionId: COLLECTION,
|
|
documentId: date,
|
|
data: {'hours': hours, 'mood': mood, 'comments': comments},
|
|
);
|
|
|
|
print("Updated $date.");
|
|
|
|
_entries.removeAt(entryIndex);
|
|
_entries.add(newEntry);
|
|
notifyListeners();
|
|
return newEntry;
|
|
}
|
|
|
|
updateHours(dayEntry, index, value) {
|
|
List<dynamic> hours = dayEntry.data['hours'];
|
|
try {
|
|
hours[index] = num.parse(value);
|
|
} catch (e) {
|
|
if (hours.length == index) {
|
|
hours.add(num.parse(value));
|
|
} else {
|
|
hours.addAll(List.generate(index - hours.length, (i) => -1));
|
|
hours.add(num.parse(value));
|
|
}
|
|
}
|
|
updateEntry(dateISO: dayEntry.data['date'], hours: hours);
|
|
}
|
|
|
|
Future<Document> addEntry(
|
|
{required String date,
|
|
List hours = const [],
|
|
dynamic mood,
|
|
String comments = ""}) async {
|
|
|
|
return databases.createDocument(
|
|
databaseId: APPWRITE_DATABASE_ID,
|
|
collectionId: COLLECTION,
|
|
documentId: date,
|
|
data: {
|
|
'date': date,
|
|
'hours': hours,
|
|
'mood': mood,
|
|
'comments': comments
|
|
});
|
|
}
|
|
|
|
Future<dynamic> deleteEntry({required String date}) {
|
|
return databases.deleteDocument(
|
|
databaseId: APPWRITE_DATABASE_ID,
|
|
collectionId: COLLECTION,
|
|
documentId: date);
|
|
}
|
|
}
|