finish save data
This commit is contained in:
228
lib/controller/home_controller.dart
Normal file
228
lib/controller/home_controller.dart
Normal file
@@ -0,0 +1,228 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class HomeController extends GetxController {
|
||||
final isloadingData = false.obs;
|
||||
final box = GetStorage();
|
||||
final listKantine = <dynamic>[].obs;
|
||||
final newBelegName = '?'.obs;
|
||||
final newBelegDate = '?'.obs;
|
||||
final newBelegBetrag = '?'.obs;
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
await _loadFromNotionKantine();
|
||||
// Initialize any necessary data or services here
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {}
|
||||
|
||||
Future<void> _loadFromNotionKantine() async {
|
||||
isloadingData(true);
|
||||
var postUrl = box.read('BASEURL');
|
||||
var baeraToken = box.read('TOKEN'); // baeraToken aus GetStorage lesen
|
||||
var headers = Map<String, String>.from(box.read('HEADERS') ?? {});
|
||||
headers['Authorization'] = 'Bearer $baeraToken';
|
||||
var httpClient = GetHttpClient(timeout: const Duration(seconds: 20));
|
||||
var response = await httpClient.post(postUrl, headers: headers);
|
||||
if (response.isOk) {
|
||||
// Parse the response data and update your UI accordingly
|
||||
var data = response.body;
|
||||
var allJsonDataDynamicList = (data['results']);
|
||||
for (var item in allJsonDataDynamicList) {
|
||||
Map<String, dynamic> properties =
|
||||
item['properties'] as Map<String, dynamic>;
|
||||
properties['id'] = item['id'];
|
||||
listKantine.add(properties);
|
||||
}
|
||||
listKantine.removeWhere((element) => element['Gelöscht']['number'] == 1);
|
||||
listKantine.sort((a, b) {
|
||||
var dateA = DateTime.parse(a['Verkaufsdatum']['date']['start']);
|
||||
var dateB = DateTime.parse(b['Verkaufsdatum']['date']['start']);
|
||||
return dateB.compareTo(dateA); // Sort in descending order
|
||||
});
|
||||
} else {
|
||||
// Handle error
|
||||
print('Error: ${response.statusCode}');
|
||||
}
|
||||
isloadingData(false);
|
||||
httpClient.close();
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> addBeleg() async {
|
||||
var dateFormat = DateFormat('yyyy-MM-dd');
|
||||
DateTime selectedDate = DateTime.now(); // Standardwert für das Datum
|
||||
await Get.defaultDialog(
|
||||
title: 'Beleg hinzufügen',
|
||||
content: Column(
|
||||
children: [
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Beleg Name',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
onChanged: (value) {
|
||||
newBelegName(value); // Beleg Name speichern
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
DateTime? pickedDate = await showDatePicker(
|
||||
context: Get.context!,
|
||||
initialDate: selectedDate,
|
||||
firstDate: DateTime(2025),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
if (pickedDate != null) {
|
||||
selectedDate = pickedDate;
|
||||
newBelegDate.value = dateFormat.format(
|
||||
selectedDate,
|
||||
); // Datum speichern
|
||||
}
|
||||
},
|
||||
child: Obx(
|
||||
() => Text(
|
||||
'Datum auswählen: ${newBelegDate.value == '?' ? 'Kein Datum' : dateFormat.format(selectedDate)}',
|
||||
style: TextStyle(
|
||||
color: newBelegDate.value == '?' ? Colors.red : Colors.black,
|
||||
fontSize: 20,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Beleg Betrag',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
onChanged: (value) {
|
||||
newBelegBetrag(value); // Beleg Betrag speichern
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
textConfirm: 'Hinzufügen',
|
||||
textCancel: 'Abbrechen',
|
||||
confirmTextColor: Colors.white,
|
||||
cancelTextColor: Colors.red,
|
||||
buttonColor: Colors.blue,
|
||||
onCancel: () {
|
||||
// Handle cancel action
|
||||
Get.back();
|
||||
},
|
||||
onConfirm: () {
|
||||
// Handle adding the receipt
|
||||
print('Beleg Name: ${newBelegName.value}');
|
||||
print('Beleg Datum: ${newBelegDate.value}');
|
||||
print('Beleg Betrag: ${newBelegBetrag.value}');
|
||||
Get.back();
|
||||
},
|
||||
);
|
||||
update();
|
||||
_saveData();
|
||||
}
|
||||
|
||||
Map<String, dynamic> currentBodyItem(
|
||||
String currentDate,
|
||||
String preis,
|
||||
String belegName,
|
||||
String dbId,
|
||||
) {
|
||||
return {
|
||||
'parent': {'database_id': dbId},
|
||||
'properties': {
|
||||
'Verkaufsdatum': {
|
||||
'date': {'start': currentDate},
|
||||
},
|
||||
'Gelöscht': {'number': 0},
|
||||
'Betrag': {'number': double.parse(preis)},
|
||||
'BelegName': {
|
||||
'id': 'title',
|
||||
'type': 'title',
|
||||
'title': [
|
||||
{
|
||||
'type': 'text',
|
||||
'text': {'content': belegName},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> _saveData() async {
|
||||
isloadingData(true);
|
||||
var dbId = 'd036c0bc06304126aedaa8c5ad92b406';
|
||||
var baeraToken = box.read('TOKEN');
|
||||
var saveUrl = 'https://api.notion.com/v1/pages/';
|
||||
var headers = Map<String, String>.from(box.read('HEADERS') ?? {});
|
||||
headers['Authorization'] = 'Bearer $baeraToken';
|
||||
var kantinData = currentBodyItem(
|
||||
newBelegDate.value,
|
||||
newBelegBetrag.value,
|
||||
newBelegName.value,
|
||||
dbId,
|
||||
);
|
||||
var httpClient = GetHttpClient(timeout: const Duration(seconds: 20));
|
||||
await httpClient
|
||||
.post(saveUrl, headers: headers, body: kantinData)
|
||||
.then((response) {
|
||||
if (response.isOk) {
|
||||
print('Beleg erfolgreich hinzugefügt');
|
||||
_loadFromNotionKantine();
|
||||
} else {
|
||||
print('Fehler beim Hinzufügen des Belegs: ${response.statusCode}');
|
||||
}
|
||||
})
|
||||
.catchError((error) {
|
||||
print('Fehler: $error');
|
||||
})
|
||||
.whenComplete(() {
|
||||
httpClient.close();
|
||||
});
|
||||
newBelegName.value = '?';
|
||||
newBelegDate.value = '?';
|
||||
newBelegBetrag.value = '?';
|
||||
isloadingData(false);
|
||||
update();
|
||||
}
|
||||
|
||||
void deleteBeleg(stringItem, index) {
|
||||
isloadingData(true);
|
||||
print(stringItem);
|
||||
var baeraToken = box.read('TOKEN');
|
||||
var delUrl = 'https://api.notion.com/v1/pages/$stringItem/';
|
||||
var headers = Map<String, String>.from(box.read('HEADERS') ?? {});
|
||||
headers['Authorization'] = 'Bearer $baeraToken';
|
||||
var httpClient = GetHttpClient(timeout: const Duration(seconds: 20));
|
||||
var updateMap = {
|
||||
'properties': {
|
||||
'Gelöscht': {'number': 1},
|
||||
},
|
||||
};
|
||||
httpClient
|
||||
.patch(delUrl, headers: headers, body: updateMap)
|
||||
.then((response) {
|
||||
if (response.isOk) {
|
||||
print('Beleg erfolgreich gelöscht');
|
||||
} else {
|
||||
print('Fehler beim Löschen des Belegs: ${response.statusCode}');
|
||||
}
|
||||
})
|
||||
.catchError((error) {
|
||||
print('Fehler: $error');
|
||||
})
|
||||
.whenComplete(() {
|
||||
httpClient.close();
|
||||
});
|
||||
listKantine.removeAt(index);
|
||||
isloadingData(false);
|
||||
update();
|
||||
}
|
||||
}
|
||||
141
lib/main.dart
141
lib/main.dart
@@ -1,6 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:io';
|
||||
|
||||
void main() {
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
|
||||
import '../../utils/http_overrides.dart';
|
||||
import '../../pages/home/home_view.dart';
|
||||
import '../../utils/sample_routes.dart';
|
||||
|
||||
void main() async {
|
||||
await GetStorage.init();
|
||||
HttpOverrides.global = MyHttpOverrides();
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
@@ -10,113 +20,32 @@ class MyApp extends StatelessWidget {
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter Demo',
|
||||
final boxSettings = GetStorage();
|
||||
// Eine Map definieren
|
||||
bool isNoSettings = boxSettings.hasData('BASEURL');
|
||||
if (isNoSettings == false) {
|
||||
_preSetDataInLocalStorage(boxSettings);
|
||||
}
|
||||
|
||||
return GetMaterialApp(
|
||||
debugShowCheckedModeBanner: false, // Debug-Banner deaktivieren
|
||||
title: 'Kantine Ausgaben',
|
||||
theme: ThemeData(
|
||||
// This is the theme of your application.
|
||||
//
|
||||
// TRY THIS: Try running your application with "flutter run". You'll see
|
||||
// the application has a purple toolbar. Then, without quitting the app,
|
||||
// try changing the seedColor in the colorScheme below to Colors.green
|
||||
// and then invoke "hot reload" (save your changes or press the "hot
|
||||
// reload" button in a Flutter-supported IDE, or press "r" if you used
|
||||
// the command line to start the app).
|
||||
//
|
||||
// Notice that the counter didn't reset back to zero; the application
|
||||
// state is not lost during the reload. To reset the state, use hot
|
||||
// restart instead.
|
||||
//
|
||||
// This works for code too, not just values: Most code changes can be
|
||||
// tested with just a hot reload.
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.grey.shade600),
|
||||
),
|
||||
home: const MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
initialRoute: HomePage.namedRoute,
|
||||
getPages: SampleRouts.samplePages,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({super.key, required this.title});
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
// how it looks.
|
||||
|
||||
// This class is the configuration for the state. It holds the values (in this
|
||||
// case the title) provided by the parent (in this case the App widget) and
|
||||
// used by the build method of the State. Fields in a Widget subclass are
|
||||
// always marked "final".
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
State<MyHomePage> createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
// so that the display can reflect the updated values. If we changed
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
// by the _incrementCounter method above.
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// TRY THIS: Try changing the color here to a specific color (to
|
||||
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
|
||||
// change color while the other colors stay the same.
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
child: Column(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
//
|
||||
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
|
||||
// action in the IDE, or press "p" in the console), to see the
|
||||
// wireframe for each widget.
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Text('You have pushed the button this many times:'),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: const Icon(Icons.add),
|
||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
|
||||
void _preSetDataInLocalStorage(GetStorage boxSettings) {
|
||||
boxSettings.write('BASEURL', 'https://api.notion.com/v1/databases/d036c0bc06304126aedaa8c5ad92b406/query');
|
||||
boxSettings.write('TOKEN', 'secret_05Q0wxvdUrJuNC1s1CuEXxO2nxdJFxiPAbWfaDKGWKo');
|
||||
Map<String, String> headers = {
|
||||
'Notion-Version': '2021-08-16',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
boxSettings.write('HEADERS', headers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
0
lib/models/home_model.dart
Normal file
0
lib/models/home_model.dart
Normal file
9
lib/pages/home/home_binding.dart
Normal file
9
lib/pages/home/home_binding.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import '../../controller/home_controller.dart';
|
||||
|
||||
class HomeBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut<HomeController>(() => HomeController());
|
||||
}
|
||||
}
|
||||
104
lib/pages/home/home_view.dart
Normal file
104
lib/pages/home/home_view.dart
Normal file
@@ -0,0 +1,104 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../controller/home_controller.dart';
|
||||
|
||||
class HomePage extends GetView<HomeController> {
|
||||
static const String namedRoute = '/home';
|
||||
const HomePage({super.key});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var homeCtrl = controller;
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
toolbarHeight: 90,
|
||||
backgroundColor: Colors.grey.shade800,
|
||||
centerTitle: true,
|
||||
title: Text(
|
||||
'Kantine Ausgaben Liste',
|
||||
style: TextStyle(color: Colors.grey.shade200, fontSize: 35.0),
|
||||
),
|
||||
),
|
||||
body: Obx(
|
||||
() =>
|
||||
homeCtrl.isloadingData.value
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: Container(
|
||||
decoration: BoxDecoration(color: Colors.grey.shade600),
|
||||
child: ListView.separated(
|
||||
itemCount: homeCtrl.listKantine.length,
|
||||
separatorBuilder:
|
||||
(context, index) =>
|
||||
Divider(color: Colors.grey.shade700),
|
||||
padding: EdgeInsets.all(10),
|
||||
physics: BouncingScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.vertical,
|
||||
primary: false,
|
||||
itemBuilder: (context, index) {
|
||||
var properties = homeCtrl.listKantine[index];
|
||||
var dateStart = properties['Verkaufsdatum']['date']['start'];
|
||||
var betrag = properties['Betrag']['number'].toString();
|
||||
var belegName = properties['BelegName']['title'][0]['plain_text'];
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade800,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Dismissible(
|
||||
key: Key(properties['id']),
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: Icon(Icons.delete),
|
||||
),
|
||||
direction: DismissDirection.endToStart,
|
||||
onDismissed: (direction) {
|
||||
homeCtrl.deleteBeleg(properties['id'], index);
|
||||
},
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
dateStart,
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade200,
|
||||
fontSize: 20.0,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
belegName,
|
||||
style: TextStyle(
|
||||
color: Colors.grey.shade400,
|
||||
fontSize: 25.0,
|
||||
),
|
||||
),
|
||||
tileColor: Colors.grey.shade800,
|
||||
textColor: Colors.grey.shade200,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
contentPadding: EdgeInsets.all(10),
|
||||
leading: Icon(Icons.money),
|
||||
trailing: Text(
|
||||
'€$betrag',
|
||||
style: TextStyle(
|
||||
color: Colors.green.shade200,
|
||||
fontSize: 30.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
homeCtrl.addBeleg(); // Add your action here
|
||||
},
|
||||
backgroundColor: Colors.grey.shade400,
|
||||
child: Icon(Icons.add),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
10
lib/utils/http_overrides.dart
Normal file
10
lib/utils/http_overrides.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
import 'dart:io';
|
||||
|
||||
class MyHttpOverrides extends HttpOverrides {
|
||||
@override
|
||||
HttpClient createHttpClient(SecurityContext? context) {
|
||||
return super.createHttpClient(context)
|
||||
..badCertificateCallback =
|
||||
(X509Certificate cert, String host, int port) => true;
|
||||
}
|
||||
}
|
||||
13
lib/utils/sample_bindings.dart
Normal file
13
lib/utils/sample_bindings.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../controller/home_controller.dart';
|
||||
|
||||
|
||||
class SampleBindings extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut<HomeController>(() => HomeController());
|
||||
}
|
||||
}
|
||||
16
lib/utils/sample_routes.dart
Normal file
16
lib/utils/sample_routes.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import './sample_bindings.dart';
|
||||
import '../../pages/home/home_view.dart';
|
||||
|
||||
class SampleRouts {
|
||||
static final sampleBindings = SampleBindings();
|
||||
static final samplePages = [
|
||||
GetPage(
|
||||
name: HomePage.namedRoute,
|
||||
binding: sampleBindings,
|
||||
page: () => const HomePage(),
|
||||
transition: Transition.leftToRight,
|
||||
),
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user