Big update: can now update entries from flutter
This commit is contained in:
parent
ca0fe7dd61
commit
0ea14e9c02
@ -137,6 +137,49 @@ class DatabaseAPI extends ChangeNotifier {
|
||||
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},
|
||||
);
|
||||
|
||||
_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 {
|
||||
print(List.generate(index - hours.length, (i) => -1));
|
||||
|
||||
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 [],
|
||||
|
||||
@ -32,27 +32,6 @@ class _TabsPageState extends State<TabsPage> {
|
||||
builder: (context, snapshot) {
|
||||
return Text(snapshot.data.toString());
|
||||
}),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 28.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Text("Edit"),
|
||||
StreamBuilder<Object>(
|
||||
stream: appBloc.editable,
|
||||
initialData: true,
|
||||
builder: (context, snapshot) {
|
||||
return Switch(
|
||||
value: bool.parse(snapshot.data.toString()),
|
||||
onChanged: (value) {
|
||||
// print(value);
|
||||
},
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: _widgets.elementAt(_selectedIndex),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
|
||||
@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:appwrite/models.dart';
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:timezone/data/latest.dart' as tz;
|
||||
|
||||
String formatDate({String format = "", String? dateISO}) {
|
||||
final DateFormat dateFormatter = DateFormat(format);
|
||||
@ -12,117 +14,35 @@ String formatDate({String format = "", String? dateISO}) {
|
||||
}
|
||||
|
||||
String hourString(int e) {
|
||||
try {
|
||||
tz.getLocation('America/Los_Angeles');
|
||||
} catch (e) {
|
||||
tz.initializeTimeZones();
|
||||
}
|
||||
|
||||
int pacificTime = tz.TZDateTime.now(tz.getLocation('America/Los_Angeles'))
|
||||
.timeZoneOffset
|
||||
.inHours;
|
||||
int localTime = DateTime.now().timeZoneOffset.inHours;
|
||||
|
||||
e = e + localTime - pacificTime;
|
||||
|
||||
var meridien = "AM";
|
||||
var hour = 12;
|
||||
if (e > 12) {
|
||||
|
||||
if (e > 24) {
|
||||
hour = e - 24;
|
||||
} else if (e > 12) {
|
||||
hour = e - 12;
|
||||
} else if (e > 0) {
|
||||
hour = e;
|
||||
}
|
||||
if (e > 11) {
|
||||
if (e > 11 && e < 24) {
|
||||
meridien = "PM";
|
||||
}
|
||||
return "${hour.toString()} $meridien";
|
||||
}
|
||||
|
||||
List<Widget> generateHours(entry, bool edit) {
|
||||
if (entry == null) {
|
||||
return [Center(child: RefreshProgressIndicator())];
|
||||
}
|
||||
List<dynamic> hours = entry.data['hours'];
|
||||
|
||||
// print(hours);
|
||||
|
||||
List reduced = [];
|
||||
int counter = 0;
|
||||
|
||||
if (edit) {
|
||||
for (int val in hours) {
|
||||
if (reduced.isEmpty) {
|
||||
reduced.add({'val': val, 'num': 1, 'hour': counter});
|
||||
} else {
|
||||
if (reduced.last['val'] == val) {
|
||||
reduced.last['num']++;
|
||||
reduced.last['hour'] = counter;
|
||||
} else {
|
||||
reduced.add({'val': val, 'num': 1, 'hour': counter});
|
||||
}
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
} else {
|
||||
for (int val in hours) {
|
||||
reduced.add({
|
||||
'hour': counter,
|
||||
'val': val,
|
||||
'num': 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return reduced.map(
|
||||
(e) {
|
||||
double height = double.parse((e['num'] * 36).toString());
|
||||
return Consumer<CategoriesAPI>(
|
||||
builder: (context, categories, child) {
|
||||
Category category = categories.lookUp(e['val'].toString());
|
||||
return SizedBox(
|
||||
height: height,
|
||||
child: Card(
|
||||
color: category.backgroundColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
e['num'] == 1
|
||||
? Center(
|
||||
child: Text(
|
||||
style:
|
||||
TextStyle(color: category.foregroundColor),
|
||||
hourString(e['hour'])),
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
style: TextStyle(
|
||||
color: category.foregroundColor),
|
||||
hourString(e['hour'] - e['num'] + 1)),
|
||||
Expanded(
|
||||
child: VerticalDivider(
|
||||
indent: 10,
|
||||
endIndent: 10,
|
||||
color: category.foregroundColor,
|
||||
width: 4,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
style: TextStyle(
|
||||
color: category.foregroundColor),
|
||||
hourString(e['hour'] + 1))
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Text(
|
||||
style: TextStyle(color: category.foregroundColor),
|
||||
category.name),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
).toList();
|
||||
}
|
||||
|
||||
Color moodColor(mood) {
|
||||
if (mood == null) {
|
||||
return Colors.transparent;
|
||||
@ -228,6 +148,8 @@ class _DayViewState extends State<DayView> {
|
||||
late num? mood = 0;
|
||||
late String comments = "";
|
||||
|
||||
bool _editable = false;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
@ -277,8 +199,8 @@ class _DayViewState extends State<DayView> {
|
||||
Widget moodWidget = mood == null
|
||||
? Icon(
|
||||
size: 30,
|
||||
Icons.star_rate_outlined,
|
||||
color: Colors.black,
|
||||
Icons.star_outline,
|
||||
color: Colors.white,
|
||||
)
|
||||
: Text(
|
||||
style: TextStyle(fontSize: 20, color: Colors.black),
|
||||
@ -290,7 +212,7 @@ class _DayViewState extends State<DayView> {
|
||||
height: 20,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: GestureDetector(
|
||||
onTap: () => _setDate(DateTime.now()),
|
||||
onLongPress: () {
|
||||
@ -326,16 +248,28 @@ class _DayViewState extends State<DayView> {
|
||||
icon: Icon(Icons.arrow_right),
|
||||
onPressed: () => _incrementDate(1),
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(width: 5),
|
||||
),
|
||||
Text("Edit"),
|
||||
Switch(
|
||||
value: _editable,
|
||||
onChanged: (value) => setState(() {
|
||||
_editable = !_editable!;
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: categories.ready
|
||||
? generateHours(dayEntry, true)
|
||||
: [CircularProgressIndicator()],
|
||||
),
|
||||
child: categories.ready
|
||||
? HourGenerator(
|
||||
dayEntry: dayEntry,
|
||||
editable: _editable,
|
||||
)
|
||||
: ListView(
|
||||
children: [Center(child: CircularProgressIndicator())]),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 30, right: 30, left: 10),
|
||||
@ -344,9 +278,45 @@ class _DayViewState extends State<DayView> {
|
||||
SizedBox(width: 10),
|
||||
SizedBox.square(
|
||||
dimension: 50,
|
||||
child: Container(
|
||||
color: moodColor(mood),
|
||||
child: Center(child: moodWidget),
|
||||
child: GestureDetector(
|
||||
onTapDown: (event) => showMenu(
|
||||
initialValue: mood,
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(
|
||||
event.globalPosition.dx + 25,
|
||||
event.globalPosition.dy - 50,
|
||||
MediaQuery.of(context).size.width -
|
||||
event.globalPosition.dx,
|
||||
MediaQuery.of(context).size.height -
|
||||
event.globalPosition.dy +
|
||||
0,
|
||||
),
|
||||
items: List.generate(
|
||||
10,
|
||||
(index) => PopupMenuItem(
|
||||
onTap: () => database.updateEntry(
|
||||
dateISO: dayEntry!.data['date'], mood: index),
|
||||
value: index,
|
||||
child: Text(
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: moodColor(index),
|
||||
),
|
||||
index.toString(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: mood == null
|
||||
? Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white)),
|
||||
child: Center(child: moodWidget),
|
||||
)
|
||||
: Container(
|
||||
color: moodColor(mood),
|
||||
child: Center(child: moodWidget),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 30),
|
||||
@ -356,12 +326,20 @@ class _DayViewState extends State<DayView> {
|
||||
smartQuotesType: SmartQuotesType.enabled,
|
||||
enableInteractiveSelection: true,
|
||||
controller: commentsController,
|
||||
minLines: 2,
|
||||
maxLines: 4,
|
||||
onFieldSubmitted: (value) {
|
||||
database.updateEntry(
|
||||
dateISO: dayEntry!.data['date'], comments: value);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(width: 30),
|
||||
IconButton(
|
||||
tooltip: "Save",
|
||||
onPressed: () => print("Save"),
|
||||
onPressed: () => database.updateEntry(
|
||||
dateISO: dayEntry!.data['date'],
|
||||
comments: commentsController.value.text.toString()),
|
||||
icon: Icon(Icons.save),
|
||||
)
|
||||
],
|
||||
@ -372,3 +350,286 @@ class _DayViewState extends State<DayView> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HourGenerator extends StatefulWidget {
|
||||
const HourGenerator(
|
||||
{super.key, required this.dayEntry, required this.editable});
|
||||
|
||||
final Document? dayEntry;
|
||||
final bool editable;
|
||||
|
||||
@override
|
||||
State<HourGenerator> createState() => _HourGeneratorState();
|
||||
}
|
||||
|
||||
class _HourGeneratorState extends State<HourGenerator> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Widget> generateHours(entry, bool edit) {
|
||||
if (entry == null) {
|
||||
return [Center(child: RefreshProgressIndicator())];
|
||||
}
|
||||
List<dynamic> hours = entry.data['hours'];
|
||||
|
||||
// print(hours);
|
||||
|
||||
List reduced = [];
|
||||
int counter = 0;
|
||||
|
||||
if (!edit) {
|
||||
for (int val in hours) {
|
||||
if (reduced.isEmpty) {
|
||||
reduced.add({'val': val, 'num': 1, 'hour': counter});
|
||||
} else {
|
||||
if (reduced.last['val'] == val) {
|
||||
reduced.last['num']++;
|
||||
reduced.last['hour'] = counter;
|
||||
} else {
|
||||
reduced.add({'val': val, 'num': 1, 'hour': counter});
|
||||
}
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
} else {
|
||||
for (int val in hours) {
|
||||
reduced.add({
|
||||
'hour': counter,
|
||||
'val': val,
|
||||
'num': 1,
|
||||
});
|
||||
if (edit) counter++;
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> hourWidgets = reduced.map(
|
||||
(e) {
|
||||
double height = double.parse((e['num'] * 36).toString());
|
||||
return Consumer<CategoriesAPI>(
|
||||
builder: (context, categories, child) {
|
||||
Category category = categories.lookUp(e['val'].toString());
|
||||
return SizedBox(
|
||||
height: height,
|
||||
child: GestureDetector(
|
||||
onTap: () {},
|
||||
child: Card(
|
||||
color: category.backgroundColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
e['num'] == 1
|
||||
? SizedBox(
|
||||
width: 50,
|
||||
child: Center(
|
||||
child: Text(
|
||||
style: TextStyle(
|
||||
color: category.foregroundColor),
|
||||
hourString(e['hour']),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10, bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
style: TextStyle(
|
||||
color: category.foregroundColor),
|
||||
hourString(e['hour'] - e['num'] + 1)),
|
||||
Expanded(
|
||||
child: VerticalDivider(
|
||||
indent: 2,
|
||||
endIndent: 2,
|
||||
color: category.foregroundColor,
|
||||
thickness: 2,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
style: TextStyle(
|
||||
color: category.foregroundColor),
|
||||
hourString(e['hour'] + 1))
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: edit
|
||||
? HourFormField(
|
||||
category: category,
|
||||
index: e['hour'],
|
||||
dayEntry: entry,
|
||||
)
|
||||
: Text(
|
||||
style: TextStyle(
|
||||
color: category.foregroundColor),
|
||||
category.name),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
).toList();
|
||||
|
||||
List<Consumer<CategoriesAPI>> remainingHours =
|
||||
List.generate(24 - counter, (index) {
|
||||
return Consumer<CategoriesAPI>(builder: (context, value, child) {
|
||||
return SizedBox(
|
||||
height: 35,
|
||||
child: Card(
|
||||
color: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 50,
|
||||
child: Center(
|
||||
child: Text(
|
||||
style: TextStyle(color: Colors.white),
|
||||
hourString(counter + index)),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: HourFormField(
|
||||
index: index + counter,
|
||||
dayEntry: entry,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
List<Consumer<CategoriesAPI>> remainingHoursConsolidated = [
|
||||
Consumer<CategoriesAPI>(
|
||||
builder: (context, value, child) {
|
||||
return SizedBox(
|
||||
height: (24 - counter) * 30,
|
||||
child: Card(
|
||||
color: Colors.black,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
style: TextStyle(color: Colors.white),
|
||||
hourString(counter)),
|
||||
Expanded(
|
||||
child: VerticalDivider(
|
||||
indent: 2,
|
||||
endIndent: 2,
|
||||
color: Colors.white,
|
||||
thickness: 2,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
style: TextStyle(color: Colors.white),
|
||||
hourString(24))
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Icon(Icons.question_mark),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
];
|
||||
|
||||
edit || counter == 23
|
||||
? hourWidgets.addAll(remainingHours)
|
||||
: hourWidgets.addAll(remainingHoursConsolidated);
|
||||
;
|
||||
return hourWidgets;
|
||||
}
|
||||
|
||||
return ListView(children: generateHours(widget.dayEntry, widget.editable));
|
||||
}
|
||||
}
|
||||
|
||||
class HourFormField extends StatefulWidget {
|
||||
HourFormField({
|
||||
super.key,
|
||||
this.category,
|
||||
required this.index,
|
||||
required this.dayEntry,
|
||||
});
|
||||
|
||||
final Category? category;
|
||||
int index;
|
||||
Document dayEntry;
|
||||
|
||||
@override
|
||||
State<HourFormField> createState() => _HourFormFieldState();
|
||||
}
|
||||
|
||||
class _HourFormFieldState extends State<HourFormField> {
|
||||
Color fgColor = Colors.white;
|
||||
|
||||
String catNum = "";
|
||||
|
||||
String catName = "[Empty]";
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.category != null) {
|
||||
catNum = widget.category!.number.toString();
|
||||
fgColor = widget.category!.foregroundColor;
|
||||
catName = widget.category!.name;
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 135,
|
||||
),
|
||||
SizedBox(
|
||||
width: 50,
|
||||
child: Consumer<DatabaseAPI>(builder: (context, database, child) {
|
||||
return TextFormField(
|
||||
showCursor: false,
|
||||
onFieldSubmitted: (value) {
|
||||
database.updateHours(widget.dayEntry, widget.index, value);
|
||||
},
|
||||
style: TextStyle(
|
||||
color: fgColor, fontFamily: "Monospace", height: 35),
|
||||
textAlign: TextAlign.center,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false,
|
||||
),
|
||||
initialValue: catNum,
|
||||
);
|
||||
}),
|
||||
),
|
||||
SizedBox(width: 40),
|
||||
Text(
|
||||
style: TextStyle(color: fgColor, fontFamily: "Monospace"), catName),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ dependencies:
|
||||
pluto_grid: ^7.0.2
|
||||
string_to_hex: ^0.2.2
|
||||
flutter_form_builder: ^9.0.0
|
||||
timezone: ^0.9.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user